Migrate to Godot 4 #1
@@ -0,0 +1,43 @@
|
||||
name: Setup Godot
|
||||
description: Download a Godot headless Linux binary and (optionally) export templates.
|
||||
|
||||
inputs:
|
||||
version:
|
||||
description: Godot version (e.g. 4.6). Templates land under <version>.stable.
|
||||
required: false
|
||||
default: "4.6"
|
||||
templates:
|
||||
description: Install export templates too. "true" / "false".
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install Godot ${{ inputs.version }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VER="${{ inputs.version }}"
|
||||
URL="https://github.com/godotengine/godot/releases/download/${VER}-stable/Godot_v${VER}-stable_linux.x86_64.zip"
|
||||
wget -q "$URL" -O /tmp/godot.zip
|
||||
mkdir -p "$HOME/bin"
|
||||
unzip -q /tmp/godot.zip -d /tmp
|
||||
mv "/tmp/Godot_v${VER}-stable_linux.x86_64" "$HOME/bin/godot"
|
||||
chmod +x "$HOME/bin/godot"
|
||||
echo "$HOME/bin" >> "$GITHUB_PATH"
|
||||
"$HOME/bin/godot" --version
|
||||
|
||||
- name: Install export templates
|
||||
if: inputs.templates == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VER="${{ inputs.version }}"
|
||||
URL="https://github.com/godotengine/godot/releases/download/${VER}-stable/Godot_v${VER}-stable_export_templates.tpz"
|
||||
wget -q "$URL" -O /tmp/templates.tpz
|
||||
DEST="$HOME/.local/share/godot/export_templates/${VER}.stable"
|
||||
mkdir -p "$DEST"
|
||||
unzip -q /tmp/templates.tpz -d /tmp/templates_extracted
|
||||
mv /tmp/templates_extracted/templates/* "$DEST/"
|
||||
ls "$DEST" | head
|
||||
@@ -0,0 +1,118 @@
|
||||
# Gitea Actions CI
|
||||
|
||||
Workflow defined in [`build.yml`](./build.yml). Triggered on push / PR to
|
||||
`dev` and `main`, or manually via `workflow_dispatch`.
|
||||
|
||||
## Jobs
|
||||
|
||||
All jobs run on the default `ubuntu-latest` runner image (which already
|
||||
ships Node, Python, git, wget, unzip, etc.). Godot is installed per-job
|
||||
via the local composite action [`.gitea/actions/setup-godot`](../actions/setup-godot/action.yml),
|
||||
which downloads the official Linux binary from the godotengine GitHub
|
||||
release and (optionally) export templates into `$HOME`.
|
||||
|
||||
| Job | Tooling installed by the job | Role |
|
||||
|------------------|---------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
|
||||
| `validate` | Godot binary (no templates) | `godot --headless --import` then grep for `SCRIPT ERROR` / `Parse Error`. Uploads `.godot/` cache. |
|
||||
| `lint` | `gdtoolkit==4.*` via `pip` | `gdlint scripts db scenes`. Parallel to `validate`; does not gate exports yet. |
|
||||
| `export-desktop` | Godot binary + export templates | Matrix: Windows / Linux / macOS. Reuses the import cache, uploads each binary as artifact. |
|
||||
| `export-android` | Godot binary + export templates + JDK 17 + Android SDK (under `$GITHUB_WORKSPACE/.android-sdk`) | Provisions keystore, writes `editor_settings-4.tres` with SDK / JDK paths, exports APK. |
|
||||
|
||||
Artifacts are kept 14 days, accessible from the Gitea run page.
|
||||
|
||||
## Prerequisites before the first successful run
|
||||
|
||||
1. **Godot version** — `GODOT_VERSION` is set at the top of the workflow
|
||||
(currently `4.6`). The setup action expects a stable release on the
|
||||
godotengine GitHub releases page; bump in lockstep with the project.
|
||||
2. **macOS preset missing** — add it in Godot Editor → Project → Export →
|
||||
Add → macOS, name it exactly `macOS` (or change the matrix entry). The
|
||||
`.zip` will be unsigned; on Mac it needs
|
||||
`xattr -dr com.apple.quarantine` to launch.
|
||||
3. **`Linux/X11Debug` preset** — Godot-3-era name. Reopen the project in
|
||||
Godot 4 once and re-save the preset (the editor may rename it). Update
|
||||
the matrix `preset:` field accordingly if it does.
|
||||
4. **Gitea runner** — `act_runner` with the default
|
||||
`catthehacker/ubuntu:act-latest` image is enough; no Docker-in-Docker
|
||||
needed now that no job uses `container:`. The runner must reach
|
||||
`github.com` (for actions + Godot release downloads) and
|
||||
`dl.google.com` (for the Android SDK).
|
||||
5. **Optional secret** `ANDROID_KEYSTORE_BASE64` — `base64 -w0 debug.keystore`,
|
||||
stored as a Gitea repo secret. Without it, a throwaway keystore is
|
||||
generated per run, so the APK signature changes every build.
|
||||
|
||||
## Linting
|
||||
|
||||
`gdlint` (from Scony's `gdtoolkit`) runs in the `lint` job over `scripts/`,
|
||||
`db/`, and `scenes/`. `addons/` (third-party LOD plugin) and `developers/`
|
||||
(sandbox) are intentionally excluded.
|
||||
|
||||
The job is **non-blocking** today — the export jobs only depend on
|
||||
`validate`, so a lint failure prints warnings but still produces binaries.
|
||||
Once the codebase is clean, switch the export jobs' `needs: validate` to
|
||||
`needs: [validate, lint]` to make lint a hard gate.
|
||||
|
||||
Suppress specific rules per-line with `# gdlint: disable=<rule>` or
|
||||
project-wide with a `gdlintrc` file at the repo root (see
|
||||
[gdtoolkit docs](https://github.com/Scony/godot-gdscript-toolkit/wiki)).
|
||||
|
||||
## Known issues from first runs
|
||||
|
||||
Captured from the first triggered runs on `feature/godot-migration`
|
||||
(2026-05-17). Both must be resolved before the workflow can pass.
|
||||
|
||||
### 1. Container jobs failed with `node: not found` (resolved 2026-05-17)
|
||||
|
||||
The first runs used `container: barichello/godot-ci:4.6` for the Godot
|
||||
jobs. That image does not ship Node.js, so `actions/checkout@v4` (a JS
|
||||
action) crashed at startup with
|
||||
`OCI runtime exec failed: exec: "node": executable file not found`.
|
||||
|
||||
Resolved by removing every `container:` block. The runner's default
|
||||
`catthehacker/ubuntu:act-latest` image already has Node / Python / git /
|
||||
JDK, and Godot is now installed at the start of each job via the local
|
||||
composite action `.gitea/actions/setup-godot/`.
|
||||
|
||||
### 2. `actions/checkout` clones the wrong URL (resolved 2026-05-17)
|
||||
|
||||
The first runs failed at clone time because the runner asked for
|
||||
`https://dev.stilobique.com/darknight/puzzle-quest/info/refs` while
|
||||
Gitea was mounted under `/gitea/` behind YunoHost — the request was
|
||||
intercepted by the YunoHost SSO at the root and redirected before
|
||||
reaching Gitea.
|
||||
|
||||
Resolved by relocating Gitea to the root: it now serves at
|
||||
`https://dev.stilobique.com/` directly (API at `/api/v1/...`,
|
||||
`clone_url` at `/<owner>/<repo>.git`). The runner-injected
|
||||
`GITHUB_SERVER_URL` and the actual Gitea base URL now agree.
|
||||
|
||||
If Gitea is ever moved back under a sub-path, the fix is `ROOT_URL` in
|
||||
`app.ini` (`[server] ROOT_URL = https://<host>/<prefix>/`) or
|
||||
re-registering `act_runner` with the full instance URL.
|
||||
|
||||
### 3. Default-branch mismatch
|
||||
|
||||
The Gitea API reports `default_branch: main` for the repo, but
|
||||
`CLAUDE.md` describes `dev` as the default. The workflow listens to both,
|
||||
so jobs trigger correctly either way, but the "Workflows" sidebar in the
|
||||
Gitea UI reads from whatever the actual default branch is. If you intend
|
||||
`dev` to be the default, update it under repo Settings → Branches.
|
||||
|
||||
## Differences from the old `.drone.yml`
|
||||
|
||||
- No more Drone, no more Butler — build only, artifacts downloadable from
|
||||
the Gitea UI.
|
||||
- GDScript validation step before export (didn't exist).
|
||||
- `.godot/` import cache shared between jobs (faster reruns).
|
||||
- Keystore via Gitea secret instead of a public pCloud link.
|
||||
- macOS target added (preset still to be created in Godot).
|
||||
- `master` / empty `ReleaseVersion` pipeline → replaced by triggers on
|
||||
`main` (release branch per `CLAUDE.md`).
|
||||
|
||||
## Future: itch.io deploy via Butler
|
||||
|
||||
Not wired. When you want it back, add a `deploy-itch` job gated on tag
|
||||
push (`v*`) that downloads the artifacts and runs
|
||||
`butler push <dir> dev-crea/ahog:<channel>` with `BUTLER_API_KEY` from
|
||||
secrets. Channels used historically:
|
||||
`windows`, `linux`, `android`, `mac`.
|
||||
@@ -0,0 +1,217 @@
|
||||
name: Build Puzzle Quest
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [dev, main, feature/godot-migration]
|
||||
pull_request:
|
||||
branches: [dev, main]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
GODOT_VERSION: "4.6"
|
||||
|
||||
jobs:
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. GDScript validation — parse every script and fail on errors / warnings.
|
||||
# ---------------------------------------------------------------------------
|
||||
validate:
|
||||
name: Validate GDScript
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: ./.gitea/actions/setup-godot
|
||||
with:
|
||||
version: ${{ env.GODOT_VERSION }}
|
||||
|
||||
- name: Import project (parses every .gd / .tscn)
|
||||
run: |
|
||||
godot --headless --import 2>&1 | tee /tmp/godot-import.log || true
|
||||
|
||||
- name: Fail on parse / script errors
|
||||
run: |
|
||||
if grep -qE "SCRIPT ERROR|Parse Error|ERROR: .*\.gd" /tmp/godot-import.log; then
|
||||
echo "::error::GDScript errors detected during import"
|
||||
grep -E "SCRIPT ERROR|Parse Error|ERROR: .*\.gd" /tmp/godot-import.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Static analysis — gdlint from Scony's gdtoolkit (Python, no Godot).
|
||||
# Runs in parallel with `validate`. Exports do NOT depend on this job,
|
||||
# so a lint failure does not block builds while the Godot-3 leftovers
|
||||
# are still being cleaned up. Once the tree is clean, add this job to
|
||||
# the `needs:` of the export jobs to make it a hard gate.
|
||||
# ---------------------------------------------------------------------------
|
||||
lint:
|
||||
name: Lint GDScript
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install gdtoolkit
|
||||
run: |
|
||||
python3 -m venv /tmp/gdlint-venv
|
||||
/tmp/gdlint-venv/bin/pip install --quiet "gdtoolkit==4.*"
|
||||
echo "/tmp/gdlint-venv/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Run gdlint
|
||||
run: gdlint scripts db scenes
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. Desktop exports — runs in parallel.
|
||||
# macOS is commented out until a preset is added in the Godot editor
|
||||
# (export_presets.cfg has none today). Restore the entry once the preset
|
||||
# exists; the matrix is otherwise ready to take it.
|
||||
# ---------------------------------------------------------------------------
|
||||
export-desktop:
|
||||
name: Export ${{ matrix.platform }}
|
||||
needs: validate
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- platform: Windows
|
||||
preset: WindowsDebug
|
||||
output: releases/windows/Puzzle-Quest.exe
|
||||
artifact_path: releases/windows
|
||||
- platform: Linux
|
||||
preset: Linux/X11Debug
|
||||
output: releases/linux/Puzzle-Quest.x86_64
|
||||
artifact_path: releases/linux
|
||||
# - platform: macOS
|
||||
# preset: macOS
|
||||
# output: releases/macos/Puzzle-Quest.zip
|
||||
# artifact_path: releases/macos
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: ./.gitea/actions/setup-godot
|
||||
with:
|
||||
version: ${{ env.GODOT_VERSION }}
|
||||
templates: "true"
|
||||
|
||||
- name: Import project
|
||||
run: godot --headless --import || true
|
||||
|
||||
- name: Prepare output dir
|
||||
run: mkdir -p "${{ matrix.artifact_path }}"
|
||||
|
||||
- name: Export ${{ matrix.platform }}
|
||||
run: godot --headless --export-debug "${{ matrix.preset }}" "${{ matrix.output }}"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PuzzleQuest-${{ matrix.platform }}
|
||||
path: ${{ matrix.artifact_path }}
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Android export — Godot + JDK 17 + Android SDK installed in $HOME.
|
||||
# Provide ANDROID_KEYSTORE_BASE64 as a Gitea secret for a stable signature;
|
||||
# otherwise a fresh debug keystore is generated on each run.
|
||||
# ---------------------------------------------------------------------------
|
||||
export-android:
|
||||
name: Export Android
|
||||
needs: validate
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
ANDROID_HOME: ${{ github.workspace }}/.android-sdk
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: ./.gitea/actions/setup-godot
|
||||
with:
|
||||
version: ${{ env.GODOT_VERSION }}
|
||||
templates: "true"
|
||||
|
||||
- name: Install JDK 17
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends openjdk-17-jdk
|
||||
echo "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Install Android command-line tools + SDK
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$ANDROID_HOME/cmdline-tools"
|
||||
wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /tmp/cmdline.zip
|
||||
unzip -q /tmp/cmdline.zip -d "$ANDROID_HOME/cmdline-tools"
|
||||
mv "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/latest"
|
||||
# `yes |` returns 141 (SIGPIPE) under `set -o pipefail` once sdkmanager
|
||||
# closes its stdin — feed a finite stream of "y" answers instead.
|
||||
printf 'y\n%.0s' {1..50} | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --licenses >/dev/null
|
||||
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" \
|
||||
"platform-tools" "platforms;android-34" "build-tools;34.0.0" >/dev/null
|
||||
|
||||
- name: Provision debug keystore
|
||||
env:
|
||||
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
|
||||
run: |
|
||||
if [ -n "${ANDROID_KEYSTORE_BASE64:-}" ]; then
|
||||
echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > /tmp/debug.keystore
|
||||
else
|
||||
keytool -keyalg RSA -genkeypair -alias androiddebugkey -keypass android \
|
||||
-keystore /tmp/debug.keystore -storepass android \
|
||||
-dname "CN=Android Debug,O=Android,C=US" -validity 9999
|
||||
fi
|
||||
# Godot rejects exports unless all three keystore/debug{,_user,_password}
|
||||
# are set together (or all three empty) — patch every one.
|
||||
sed -i 's@keystore/debug=".*"@keystore/debug="/tmp/debug.keystore"@g' export_presets.cfg
|
||||
sed -i 's@keystore/debug_user=".*"@keystore/debug_user="androiddebugkey"@g' export_presets.cfg
|
||||
sed -i 's@keystore/debug_password=".*"@keystore/debug_password="android"@g' export_presets.cfg
|
||||
|
||||
- name: Write Godot editor settings (Android SDK / JDK paths)
|
||||
run: |
|
||||
mkdir -p ~/.config/godot
|
||||
# Godot 4.5+ uses a minor-version-suffixed settings file
|
||||
# (editor_settings-4.6.tres for 4.6), not the major-only -4.tres.
|
||||
cat > ~/.config/godot/editor_settings-${GODOT_VERSION}.tres <<EOF
|
||||
[gd_resource type="EditorSettings" format=3]
|
||||
[resource]
|
||||
export/android/android_sdk_path = "${ANDROID_HOME}"
|
||||
export/android/java_sdk_path = "/usr/lib/jvm/java-17-openjdk-amd64"
|
||||
export/android/debug_keystore = "/tmp/debug.keystore"
|
||||
export/android/debug_keystore_user = "androiddebugkey"
|
||||
export/android/debug_keystore_pass = "android"
|
||||
EOF
|
||||
|
||||
- name: Import project
|
||||
run: godot --headless --import || true
|
||||
|
||||
- name: Prepare output dir
|
||||
run: mkdir -p releases/android
|
||||
|
||||
- name: Export Android APK
|
||||
run: godot --headless --export-debug "AndroidDebug" "releases/android/Puzzle-Quest.apk"
|
||||
|
||||
- name: Sign + verify APK
|
||||
run: |
|
||||
set -euo pipefail
|
||||
APK="releases/android/Puzzle-Quest.apk"
|
||||
APKSIGNER="$ANDROID_HOME/build-tools/34.0.0/apksigner"
|
||||
# Godot 4.6 sometimes ships an unsigned APK from the headless
|
||||
# export (sign step skips silently when its internal apksigner
|
||||
# call can't locate java). Re-sign unconditionally — idempotent
|
||||
# if Godot did sign, and guarantees a valid APK if it didn't.
|
||||
"$APKSIGNER" sign \
|
||||
--ks /tmp/debug.keystore \
|
||||
--ks-pass pass:android \
|
||||
--ks-key-alias androiddebugkey \
|
||||
--key-pass pass:android \
|
||||
--v1-signing-enabled true \
|
||||
--v2-signing-enabled true \
|
||||
--v3-signing-enabled true \
|
||||
"$APK"
|
||||
"$APKSIGNER" verify --verbose "$APK"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PuzzleQuest-Android
|
||||
path: releases/android
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
+13
-2
@@ -3,8 +3,17 @@
|
||||
|
||||
### Godot ###
|
||||
|
||||
# Godot-specific ignores
|
||||
# Godot 3.x cache directory (replaced by .godot/ in Godot 4.x)
|
||||
.import/
|
||||
|
||||
# Godot 4.x project cache (re-generated on open; do not commit)
|
||||
.godot/
|
||||
|
||||
# Android build template directory generated by the editor
|
||||
# (the .gdignore file is kept; everything else under android/ is build output)
|
||||
android/*
|
||||
!android/.gdignore
|
||||
|
||||
export.cfg
|
||||
|
||||
# Imported translations (automatically generated from CSV files)
|
||||
@@ -58,7 +67,9 @@ $RECYCLE.BIN/
|
||||
# End of https://www.toptal.com/developers/gitignore/api/godot,linux,windows
|
||||
|
||||
# Ignore folders releases and build Android
|
||||
releases
|
||||
# (the .gdignore marker is tracked so Godot skips scanning this directory)
|
||||
releases/*
|
||||
!releases/.gdignore
|
||||
|
||||
# Ignore override godot
|
||||
override.cfg
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
# Puzzle Quest
|
||||
|
||||
Hidden-object game built with **Godot 4.6** (single renderer: Forward+).
|
||||
Branched from a Godot 3.3 codebase — migration is recent, expect leftover
|
||||
Godot-3-isms to occasionally surface.
|
||||
|
||||
## Run
|
||||
|
||||
```
|
||||
godot --editor # open project in the editor
|
||||
godot # run the main scene (scenes/Main.tscn)
|
||||
```
|
||||
|
||||
The system package `godot` (Arch `extra/godot`) is the project's Godot. There
|
||||
is no in-repo Godot binary.
|
||||
|
||||
## Architecture
|
||||
|
||||
**Autoloads** (declared in `project.godot [autoload]`, loaded in this order):
|
||||
|
||||
| Name | Source | Role |
|
||||
|------------------|---------------------------------------|-------------------------------------------------------------------|
|
||||
| `Loading` | `scenes/UI/loading/Loading.tscn` | Full-screen transition overlay (BG + animated border + progress) |
|
||||
| `Global` | `scripts/Global.gd` | Async scene loader (`goto_scene(path)`) + `database` reference |
|
||||
| `Setting` | `scripts/Setting.gd` | Reads/writes the settings table; applies locale/resolution/fullscreen |
|
||||
| `Event` | `scripts/Event.gd` | Static handlers connected to scene buttons (Warcraft / Home / reset / back) |
|
||||
| `GlobalAnimation`| `scripts/Animation.gd` | Tween-based dissolve + HUD slide/warning animations |
|
||||
|
||||
**Database (`scripts/Database.gd`)**
|
||||
|
||||
- Plain JSON at `db/ahog.json`. Three tables: `settings`, `levels`, `scenes`.
|
||||
- On Android the file is copied once to `user://database.json` and written
|
||||
there (game saves modify lock state per item).
|
||||
- `Global.database` is a `Database.DB` instance exposing
|
||||
`get_table_by_name(name)` and `save_db()`. Each `Table` exposes
|
||||
`get_data_at_row_idx(row_id)`, `edit_data(prop_id, row_id, value)`,
|
||||
`m_rows_count`, `get_data_by_prop_name_and_data(prop_name, value)`,
|
||||
`get_dictionary_by_prop_name_and_data(prop_name, value)`.
|
||||
- `db/M*.gd` are typed accessors (MBase / MScene / MLevel / MSetting) that
|
||||
read rows via the API above — extend these, not the JSON shape directly.
|
||||
|
||||
**Scene transitions** (`Global.goto_scene(path)`)
|
||||
|
||||
Uses `ResourceLoader.load_threaded_request` + `load_threaded_get_status` +
|
||||
`load_threaded_get` (Godot 4 API; the original `load_interactive`/`poll()`
|
||||
was removed). The Loading overlay (autoload) plays `BorderAnim` while the
|
||||
new scene loads in a background thread; `Event._loading_is_started/finished`
|
||||
flip `Global.loaded` so the poll only runs once the entry animation has set
|
||||
the boolean. Don't call `current_scene.queue_free()` outside this function
|
||||
— it will leak the resource and break the loader state.
|
||||
|
||||
**Levels.tscn / level scenes**
|
||||
|
||||
`scenes/levels/Levels.tscn` is the shared shell; concrete levels
|
||||
(`warcraft/WarCraft.tscn`, `home/Home.tscn`) inherit from it. Each scene
|
||||
has a `HiddenObjectsItems/<Item>` `MeshInstance3D` with an `Area3D`
|
||||
collision shape; clicking it triggers `Levels._check_collider` →
|
||||
`_start_dissolve(name)` → `GlobalAnimation.start_dissolve(mesh, material)`
|
||||
which runs the dissolve shader on `material.dissolve_amount`.
|
||||
|
||||
The runtime hidden-object list lives under
|
||||
`scenes/levels/parts/ListObjects.tscn` and is populated dynamically from
|
||||
the `scenes` table for the current `Global.current_scene_int`.
|
||||
|
||||
## Migration notes (Godot 3 → 4)
|
||||
|
||||
The conversion is mostly done but a few classes of mistake keep surfacing
|
||||
because `godot --convert-3to4` does not handle them:
|
||||
|
||||
- **Label**: `align/valign` → `horizontal_alignment/vertical_alignment`.
|
||||
- **Button**: `pressed` (property) → `button_pressed`; `set_pressed()` →
|
||||
assignment to `button_pressed`. The `pressed` *signal* still exists.
|
||||
- **ScrollContainer**: `scroll_horizontal_enabled = false` →
|
||||
`horizontal_scroll_mode = 0` (and same for vertical). ScrollContainer
|
||||
also ships a non-empty default panel style in Godot 4 — set
|
||||
`theme_override_styles/panel = StyleBoxEmpty` if you need transparency.
|
||||
- **TextureRect / TextureButton**: `expand = true` → `expand_mode = 1`.
|
||||
`stretch_mode` enum values **shifted down by 1** between 3 and 4 (the
|
||||
deprecated "Scale on Expand" at index 0 was removed): G3's Tile (2) is
|
||||
G4's Tile (1), G3's Keep (3) is G4's Keep (2), etc.
|
||||
- **Environment**: `background_mode` enum changed (G3 3=Sky → G4 2=Sky;
|
||||
G4 3 is Canvas which renders black). `background_sky` → `sky`;
|
||||
`background_energy` → `background_energy_multiplier`;
|
||||
`fog_color` → `fog_light_color`; `fog_height_min` → `fog_height`;
|
||||
`fog_mode = 1` (Depth) needed to keep `fog_depth_*` semantics, otherwise
|
||||
Godot 4 falls back to dense `fog_density` exponential fog.
|
||||
- **AnimationPlayer**: `add_animation(name, anim)` removed — go through
|
||||
`get_animation_library("")` (create one with `add_animation_library("")`
|
||||
if it returns null) and call `lib.add_animation(name, anim)`.
|
||||
- **Tween**: no longer a Node — call `create_tween()` from any Node and use
|
||||
`tween.tween_method(...)`. Delete any `[node type="Tween"]` from older
|
||||
`.tscn` files (the loader will crash otherwise).
|
||||
- **PhysicsRayQuery**: `space_state.intersect_ray(from, to, ...)` →
|
||||
`PhysicsRayQueryParameters3D.create(from, to)`, set fields, then
|
||||
`space_state.intersect_ray(query)`.
|
||||
- **PackedScene.instance()** → `instantiate()`.
|
||||
- **String / cast operators**: `String(x)` constructor doesn't exist — use
|
||||
`str(x)`. `x as int/String/bool` does **not** parse strings — use
|
||||
`int(s)`, `str(x)`, `bool(int(s))`.
|
||||
- **Internationalization**: project setting is `[internationalization]
|
||||
locale/translations=...`, not `[locale] translations=...`. Locale codes
|
||||
must match `.po` filenames exactly (`fr.po` → `"fr"`; G3-style `fr_FR`
|
||||
no longer auto-falls-back).
|
||||
- **Inherited scenes**: nodes from an instanced child scene need
|
||||
`layout_mode = 1` + `anchors_preset = 15` explicitly set in the parent
|
||||
scene file, otherwise Godot 4 treats them as Position-mode and zeroes
|
||||
the anchors. Watch for stale per-Label `layout_mode = 0` /
|
||||
`anchor_right = 0` overrides in Main.tscn-style parent scenes.
|
||||
|
||||
## Plugins
|
||||
|
||||
- `addons/lod/` — Calinou's Level-of-Detail plugin (Spatial / OmniLight /
|
||||
SpotLight / Particles → 3D variants). Class declarations use the Godot 4
|
||||
form (`@icon("...") class_name X` + `extends Node3D` separately).
|
||||
- `addons/godot_db_manager/` — **removed during migration**. Don't restore
|
||||
it; it relies on `WindowDialog`/`Tabs`/`PopupPanel` which were dropped in
|
||||
Godot 4. The replacement is `scripts/Database.gd` (see above).
|
||||
|
||||
## Custom shaders / materials
|
||||
|
||||
Drop-in shaders live in `.material` resources (binary `RSCC` format) next
|
||||
to each prop. `scripts/migrate_shaders.gd` is a one-shot tool that walks
|
||||
`assets/` and rewrites the embedded shader code (Godot 3 → 4 keyword
|
||||
renames: `depth_draw_alpha_prepass`, `hint_color`, `NORMALMAP`). Re-run it
|
||||
with `godot --headless --script scripts/migrate_shaders.gd` after adding
|
||||
new materials authored in Godot 3.
|
||||
|
||||
`assets/fonts/text_outline.material` is a VisualShader graph from Godot 3
|
||||
that doesn't connect cleanly in 4 (out-of-bounds `p_from_port` errors,
|
||||
COLOR never written). It has been detached from the Summary menu labels;
|
||||
re-author it with Godot 4's built-in `theme_override_constants/outline_size`
|
||||
+ `theme_override_colors/font_outline_color` instead.
|
||||
|
||||
## Known visual issues to revisit
|
||||
|
||||
- **Baked lightmap is gone.** `scenes/levels/warcraft/WarCraft.lmbake` is
|
||||
in Godot 3's binary format (incompatible). The `LightmapGI` node still
|
||||
exists in `WarCraft.tscn` but its `light_data` reference is cleared.
|
||||
Open the scene in the editor and re-bake (Scene → Bake Lightmaps).
|
||||
- **`assets/ui/themes/tab_select/UI-level-btn-shadow.png`** is 83% opaque
|
||||
black with feathered edges (a drop-shadow texture). In Godot 4 it
|
||||
renders stretched and opaque, which looked like a black square below
|
||||
each level tile, so its `BackgroundTile` TextureRect is currently
|
||||
`visible = false`. Replace with a proper 9-patch / shader if the shadow
|
||||
effect is wanted.
|
||||
- `developers/aurelien/` is a sandbox — files there (`ui_scrolls.tscn`,
|
||||
`ui_tile.tscn`, `CheckLightmap.tscn`) still use Godot-3 property names
|
||||
in places. Not on the main flow, low priority.
|
||||
|
||||
## CI
|
||||
|
||||
Gitea Actions workflow at `.gitea/workflows/build.yml`, documented in
|
||||
`.gitea/workflows/README.md`. Three jobs: GDScript validation
|
||||
(`godot --headless --import` + error grep), desktop matrix
|
||||
(Windows / Linux / macOS), and Android. Build only — no Butler / itch.io
|
||||
deploy currently wired (channels used historically were
|
||||
`dev-crea/ahog:windows|android|linux|mac`). Drone pipeline removed.
|
||||
|
||||
Branches: default `dev`, releases from `main`. Long-running migration work
|
||||
on `feature/godot-migration`.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Don't commit `db/ahog.json` runtime mutations (lock progress saved
|
||||
during play). The README documents using `git update-index --skip-worktree`
|
||||
but the cleaner alternative is just to `git checkout db/ahog.json`
|
||||
before staging.
|
||||
- `android/`, `.godot/`, and `releases/` are in `.gitignore`. The
|
||||
`.import` sidecars next to assets **are** committed (they carry the
|
||||
stable UIDs Godot 4 generates).
|
||||
- Commit messages: imperative, English, explain the *why* (especially for
|
||||
migration commits — the next person reading the diff won't have the
|
||||
Godot 3 context).
|
||||
@@ -1,5 +1,3 @@
|
||||
[](https://drone.dev-crea.com/Athena/game-source)
|
||||
|
||||
- Hidden Object
|
||||
- Tips
|
||||
- Log on Android
|
||||
|
||||
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 8
|
||||
font_data = ExtResource( 1 )
|
||||
@@ -1,7 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 10
|
||||
font_data = ExtResource( 1 )
|
||||
@@ -1,7 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 12
|
||||
font_data = ExtResource( 1 )
|
||||
@@ -1,7 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 14
|
||||
font_data = ExtResource( 1 )
|
||||
@@ -1,6 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
font_data = ExtResource( 1 )
|
||||
@@ -1,7 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 18
|
||||
font_data = ExtResource( 1 )
|
||||
@@ -1,7 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 20
|
||||
font_data = ExtResource( 1 )
|
||||
@@ -1,7 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 22
|
||||
font_data = ExtResource( 1 )
|
||||
@@ -1,7 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 24
|
||||
font_data = ExtResource( 1 )
|
||||
@@ -1,7 +0,0 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/Roboto-Regular.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 26
|
||||
font_data = ExtResource( 1 )
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -1,34 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/debug.png-72578d6223132f8bc16d1922f9da1248.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot_db_manager/assets/tex/debug.png"
|
||||
dest_files=[ "res://.import/debug.png-72578d6223132f8bc16d1922f9da1248.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -1,34 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/gui.png-1d6d47ba1ecd00882b63b6f57f502e61.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot_db_manager/assets/tex/gui.png"
|
||||
dest_files=[ "res://.import/gui.png-1d6d47ba1ecd00882b63b6f57f502e61.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
@@ -1,38 +0,0 @@
|
||||
"""
|
||||
class GDDBConstants
|
||||
"""
|
||||
|
||||
class_name GDDBConstants
|
||||
|
||||
tool
|
||||
extends Node
|
||||
|
||||
# GDDB signature
|
||||
const c_gddb_signature = "GDDB_ver"
|
||||
|
||||
# GDDB ver
|
||||
const c_gddb_ver = "2.0"
|
||||
|
||||
# invalid id to initialize integer properties
|
||||
const c_invalid_id = -1
|
||||
|
||||
# maximum database name length
|
||||
const c_max_db_name_len = 16
|
||||
|
||||
# maximum table name length
|
||||
const c_max_table_name_len = 16
|
||||
|
||||
# characters that should not be part of the database name
|
||||
const c_invalid_characters = "`~!@#$%^&*()=+[]{}\\|;:'\",<.>/?"
|
||||
|
||||
# addon main path
|
||||
const c_addon_main_path = "res://addons/godot_db_manager/"
|
||||
|
||||
# maximum tables list width
|
||||
const c_max_tables_list_width = 400.0
|
||||
|
||||
# minimum cell width
|
||||
const c_min_cell_width = 150.0
|
||||
|
||||
# maximum cell width
|
||||
const c_max_cell_width = 400.0
|
||||
@@ -1,96 +0,0 @@
|
||||
"""
|
||||
class GDDBGlobals
|
||||
"""
|
||||
|
||||
class_name GDDBGlobals
|
||||
|
||||
tool
|
||||
extends Node
|
||||
|
||||
# a flag that tells if the tool's interface is active or not
|
||||
var m_is_interface_active : bool = false
|
||||
|
||||
# sets the active flag
|
||||
func set_interface_active(active : bool) -> void :
|
||||
m_is_interface_active = active
|
||||
|
||||
# returns true if the tool's interface is active
|
||||
func is_interface_active() -> bool :
|
||||
return m_is_interface_active
|
||||
|
||||
# returns the name of the data type
|
||||
func get_data_name(data_type : int) -> String :
|
||||
if(data_type == gddb_types.e_prop_type_bool):
|
||||
return "Bool"
|
||||
elif(data_type == gddb_types.e_prop_type_int):
|
||||
return "Integer"
|
||||
elif(data_type == gddb_types.e_prop_type_float):
|
||||
return "Float"
|
||||
elif(data_type == gddb_types.e_prop_type_string):
|
||||
return "String"
|
||||
elif(data_type == gddb_types.e_prop_type_resource):
|
||||
return "Resource"
|
||||
|
||||
print("GDDBGlobals::get_data_name(" + str(data_type) + ")")
|
||||
return "Unknown data type"
|
||||
|
||||
# returns the name of the data filter
|
||||
func get_data_filter_name(data_filter_type : int) -> String :
|
||||
if(data_filter_type == gddb_types.e_data_filter_equal):
|
||||
return "Equal"
|
||||
elif(data_filter_type == gddb_types.e_data_filter_not_equal):
|
||||
return "Not equal"
|
||||
elif(data_filter_type == gddb_types.e_data_filter_less):
|
||||
return "Less"
|
||||
elif(data_filter_type == gddb_types.e_data_filter_greater):
|
||||
return "Greater"
|
||||
elif(data_filter_type == gddb_types.e_data_filter_lequal):
|
||||
return "Less or equal"
|
||||
elif(data_filter_type == gddb_types.e_data_filter_gequal):
|
||||
return "Greater or equal"
|
||||
|
||||
print("GDDBGlobals::get_data_filter_name(" + str(data_filter_type) + ")")
|
||||
return "Unknown data filter type"
|
||||
|
||||
# checks the name of the database
|
||||
func check_db_name(db_name : String) -> bool :
|
||||
for idx in range(0, db_name.length()):
|
||||
for jdx in range(0, gddb_constants.c_invalid_characters.length()):
|
||||
if(db_name[idx] == gddb_constants.c_invalid_characters[jdx]):
|
||||
return false
|
||||
return true
|
||||
|
||||
# returns a json from a row from a table
|
||||
func get_json_from_row(table : Object, row_idx : int) -> String :
|
||||
var json = "{"
|
||||
var row = table.get_data_at_row_idx(row_idx)
|
||||
for jdx in range(0, row.size()):
|
||||
var prop = table.get_prop_at(jdx)
|
||||
json += "\"" + prop.get_prop_name() + "\":"
|
||||
json += "\"" + row[jdx].get_data() + "\""
|
||||
if(jdx < row.size() - 1):
|
||||
json += ", "
|
||||
json += "}"
|
||||
return json
|
||||
|
||||
# returns the digits count from a number
|
||||
func get_digits_count(number : int) -> int :
|
||||
if(number == 0):
|
||||
return 1
|
||||
|
||||
var digits_count = 0
|
||||
while(number > 0):
|
||||
number /= 10
|
||||
digits_count += 1
|
||||
|
||||
return digits_count
|
||||
|
||||
# replace special characters in a string to handle properly saving into database
|
||||
func handle_string(text : String) -> String :
|
||||
var string = ""
|
||||
for idx in range(0, text.length()):
|
||||
if(text[idx] == "\n"):
|
||||
string += "\\n"
|
||||
else:
|
||||
string += text[idx]
|
||||
return string
|
||||
@@ -1,45 +0,0 @@
|
||||
"""
|
||||
class GDDBTypes
|
||||
"""
|
||||
|
||||
class_name GDDBTypes
|
||||
|
||||
tool
|
||||
extends Node
|
||||
|
||||
# Database loading errors
|
||||
enum {
|
||||
e_db_invalid_file = -11,
|
||||
e_db_invalid_ver = -10,
|
||||
e_db_valid = 0
|
||||
}
|
||||
|
||||
# Property types
|
||||
enum {
|
||||
e_prop_type_bool = 0
|
||||
e_prop_type_int = 1,
|
||||
e_prop_type_float = 2,
|
||||
e_prop_type_string = 3,
|
||||
|
||||
# TODO: insert more data types here and increase e_prop_type_resource
|
||||
|
||||
e_prop_type_resource = 4,
|
||||
|
||||
e_prop_types_count
|
||||
}
|
||||
|
||||
# Data filters
|
||||
enum {
|
||||
e_data_filter_equal = 0,
|
||||
e_data_filter_not_equal = 1,
|
||||
e_data_filter_less = 2,
|
||||
e_data_filter_greater = 3,
|
||||
e_data_filter_lequal = 4, # less or equal
|
||||
e_data_filter_gequal = 5 # greater or equal
|
||||
}
|
||||
|
||||
# new table dlg type
|
||||
enum {
|
||||
e_new_dlg_type_new = 0,
|
||||
e_new_dlg_type_edit = 1
|
||||
}
|
||||
@@ -1,323 +0,0 @@
|
||||
"""
|
||||
GDDatabase class
|
||||
"""
|
||||
|
||||
class_name GDDatabase
|
||||
|
||||
extends Object
|
||||
|
||||
# database types
|
||||
enum {
|
||||
e_db_type_json = 0, # JSON database
|
||||
e_db_type_binary = 1 # binary database - to be designed / implemented
|
||||
}
|
||||
|
||||
# database type
|
||||
var m_db_type : int = e_db_type_json
|
||||
|
||||
# the id of the database
|
||||
var m_db_id : int = gddb_constants.c_invalid_id
|
||||
|
||||
# the name of the database
|
||||
var m_db_name : String = ""
|
||||
|
||||
# tables in the database
|
||||
var m_tables : Array = []
|
||||
|
||||
# the path of the database
|
||||
var m_db_filepath : String = ""
|
||||
|
||||
# if the database is not saved, it is dirty
|
||||
var m_is_dirty : bool = false
|
||||
|
||||
# sets the id of the database
|
||||
func set_db_id(db_id : int) -> void :
|
||||
m_db_id = db_id
|
||||
|
||||
# returns the database id
|
||||
func get_db_id() -> int :
|
||||
return m_db_id
|
||||
|
||||
# set the name of the database
|
||||
# the name of the database should not contain special characters
|
||||
func set_db_name(db_name : String) -> bool :
|
||||
if(!gddb_globals.check_db_name(db_name)):
|
||||
print("ERROR: GDDatabase::set_db_name(" + db_name + ") - the name of the database contains invalid characters")
|
||||
return false
|
||||
# print("GDDatabase::set_db_name(" + db_name + ")")
|
||||
m_db_name = db_name
|
||||
return true
|
||||
|
||||
# returns the name of the database
|
||||
func get_db_name() -> String :
|
||||
return m_db_name
|
||||
|
||||
# sets the database file path
|
||||
func set_db_filepath(filepath : String) -> void :
|
||||
m_db_filepath = filepath
|
||||
|
||||
# returns the path of the database
|
||||
func get_db_filepath() -> String :
|
||||
return m_db_filepath
|
||||
|
||||
# checks if a table with the name "table_name" can be added into database
|
||||
func can_add_table(table_name : String, table_id : int = -1) -> bool :
|
||||
# print("GDDatabase::can_add_table(" + table_name + ", " + str(table_id) + ")")
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].get_table_name() == table_name):
|
||||
if(m_tables[idx].get_table_id() == table_id):
|
||||
continue
|
||||
print("WARNING: GDDatabase::can_add_table(" + table_name + ", " + str(table_id) + ") - table already exists")
|
||||
return false
|
||||
return true
|
||||
|
||||
# adds a new table
|
||||
# returns the table id; if already exists, it will fire an warning on output console and returns an invalid id
|
||||
func add_table(table_name : String) -> int :
|
||||
if(!can_add_table(table_name)):
|
||||
print("WARNING: GDDatabase::add_table(" + table_name + ") - cannot add table")
|
||||
return gddb_constants.c_invalid_id
|
||||
|
||||
# print("GDDatabase::add_table(" + table_name + ") to \"" + m_db_name + "\" database")
|
||||
|
||||
var table_id = generate_new_table_id()
|
||||
var table = load(gddb_constants.c_addon_main_path + "core/db_table.gd").new()
|
||||
table.set_table_id(table_id)
|
||||
table.set_table_name(table_name)
|
||||
table.set_parent_database(self)
|
||||
m_tables.push_back(table)
|
||||
return table_id
|
||||
|
||||
# edits a table name
|
||||
func edit_table_name(table_name : String, table_id : int) -> bool :
|
||||
if(!can_add_table(table_name, table_id)):
|
||||
return false
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].get_table_id() == table_id):
|
||||
m_tables[idx].set_table_name(table_name)
|
||||
break
|
||||
return true
|
||||
|
||||
# deletes a table at index
|
||||
func delete_table_at(idx : int) -> void :
|
||||
if(idx < 0 || idx > m_tables.size() - 1):
|
||||
print("GDDatabase::delete_table_at(" + str(idx) + ") - index out of bounds")
|
||||
return
|
||||
m_tables[idx].clear()
|
||||
m_tables[idx].free()
|
||||
m_tables.remove(idx)
|
||||
|
||||
# deletes a table by id
|
||||
func delete_table_by_id(table_id: int) -> void :
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].get_table_id() == table_id):
|
||||
# print("GDDatabase::delete_table_by_id(" + str(table_id) + ")")
|
||||
m_tables[idx].clear()
|
||||
m_tables[idx].free()
|
||||
m_tables.remove(idx)
|
||||
return
|
||||
print("ERROR: GDDatabase::delete_table_by_id(" + str(table_id) + ") - cannot erase table; id not found")
|
||||
|
||||
# deletes a table by name
|
||||
func delete_table_by_name(table_name: String) -> void :
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].get_table_name() == table_name):
|
||||
# print("GDDatabase::delete_table_by_name(" + table_name + ")")
|
||||
m_tables[idx].clear()
|
||||
m_tables[idx].free()
|
||||
m_tables.remove(idx)
|
||||
return
|
||||
print("ERROR: GDDatabase::delete_table_by_name(" + table_name + ") - cannot erase table; name not found")
|
||||
|
||||
# generates a new table id
|
||||
func generate_new_table_id() -> int :
|
||||
if(m_tables.size() == 0):
|
||||
return 0
|
||||
return m_tables[m_tables.size()-1].get_table_id() + 1
|
||||
|
||||
# returns the count of the tables in the database
|
||||
func get_tables_count() -> int :
|
||||
return m_tables.size()
|
||||
|
||||
# returns true if the table exists in the database, false otherwise
|
||||
# this is equivalent with (get_table_by_name(table name) != null) function, but without firing the error in case the table doesn't exist
|
||||
func is_table_exists(table_name : String) -> bool :
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].get_table_name() == table_name):
|
||||
return true
|
||||
return false
|
||||
|
||||
# returns a table by an index or null if the index is invalid
|
||||
func get_table_at(idx: int) -> Object :
|
||||
if(idx < 0 || idx >= m_tables.size()):
|
||||
print("ERROR: GDDatabase::get_table_at(" + str(idx) + ") - cannot obtain table with index")
|
||||
return null
|
||||
return m_tables[idx]
|
||||
|
||||
# returns a table by its id or null if a table with id doesn's exist
|
||||
func get_table_by_id(table_id: int) -> Object :
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].get_table_id() == table_id):
|
||||
return m_tables[idx]
|
||||
print("ERROR: GDDatabase::get_table_by_id(" + str(table_id) + ") - cannot obtain table with id")
|
||||
return null
|
||||
|
||||
# returns a table by its name or null if the name of the table doesn's exist
|
||||
func get_table_by_name(table_name: String) -> Object :
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].get_table_name() == table_name):
|
||||
return m_tables[idx]
|
||||
print("ERROR: GDDatabase::get_table_by_id(" + table_name + ") - cannot obtain table with name")
|
||||
return null
|
||||
|
||||
# deletes all the tables
|
||||
func clear() -> void :
|
||||
# print("GDDatabase::clear()")
|
||||
m_db_name = ""
|
||||
for idx in range(0, m_tables.size()):
|
||||
m_tables[idx].clear()
|
||||
m_tables.clear()
|
||||
|
||||
# sets the database dirty; it is not saved
|
||||
func set_dirty(dirty : bool) -> void :
|
||||
m_is_dirty = dirty
|
||||
|
||||
# returns true if a database is dirty (should be saved), false otherwise
|
||||
func is_dirty() -> bool :
|
||||
return m_is_dirty
|
||||
|
||||
# serialization
|
||||
func save_db() -> void :
|
||||
if(m_db_name.empty()):
|
||||
print("ERROR: GDDatabase::save_db() - current database doesn't have a name")
|
||||
return
|
||||
|
||||
if(m_db_filepath.empty()):
|
||||
print("ERROR: GDDatabase::save_db() - current database doesn't have a path file")
|
||||
return
|
||||
|
||||
# print("GDDatabase::save_db() - " + m_db_name + " to: " + m_db_filepath)
|
||||
var text = "{"
|
||||
text += "\n\t\"" + gddb_constants.c_gddb_signature + "\":\"" + gddb_constants.c_gddb_ver + "\","
|
||||
text += "\n\t\"db_name\":\"" + m_db_name + "\","
|
||||
text += "\n\t\"tables\":["
|
||||
for idx in range(0, m_tables.size()):
|
||||
text += "\n\t\t{"
|
||||
text += "\n\t\t\t\"table_name\":\"" + m_tables[idx].get_table_name() + "\","
|
||||
text += "\n\t\t\t\"props\":["
|
||||
for jdx in range(0, m_tables[idx].get_props_count()):
|
||||
var db_prop = m_tables[idx].get_prop_at(jdx)
|
||||
text += "\n\t\t\t\t\t{"
|
||||
text += "\"name\":\"" + str(db_prop.get_prop_name()) + "\","
|
||||
|
||||
var prop_type = db_prop.get_prop_type()
|
||||
if(prop_type < gddb_types.e_prop_types_count):
|
||||
text += "\"type\":\"" + str(prop_type) + "\","
|
||||
else:
|
||||
# print("GDDatabase::save_db() - prop_type: " + str(prop_type))
|
||||
var table_id = prop_type - gddb_types.e_prop_types_count
|
||||
var table = get_table_by_id(table_id)
|
||||
if(null == table):
|
||||
print("GDDatabase::save_db() - table not found with id: " + str(table_id))
|
||||
text += "\"type\":\"" + "table" + "\","
|
||||
text += "\"table_name\":\"" + table.get_table_name() + "\","
|
||||
|
||||
text += "\"auto_increment\":\"" + str(int(db_prop.has_autoincrement())) + "\""
|
||||
|
||||
text += "}"
|
||||
if(jdx < m_tables[idx].get_props_count() - 1):
|
||||
text += ","
|
||||
text += "\n\t\t\t],"
|
||||
|
||||
text += "\n\t\t\t\"data\":["
|
||||
for jdx in range(0, m_tables[idx].get_data_size()):
|
||||
#var the_data = m_tables[idx].get_data_at(jdx)
|
||||
#print("getting data at " + str(jdx) + " : " + the_data)
|
||||
text += "\"" + m_tables[idx].get_data_at(jdx) + "\""
|
||||
if(jdx < m_tables[idx].get_data_size() - 1):
|
||||
text += ","
|
||||
text += "]" # end of data
|
||||
text += "\n\t\t}" # end of table
|
||||
|
||||
if(idx < m_tables.size() - 1):
|
||||
text += ","
|
||||
|
||||
text += "\n\t]\n}"
|
||||
|
||||
var save_file = File.new()
|
||||
save_file.open(m_db_filepath, File.WRITE)
|
||||
save_file.store_string(text)
|
||||
save_file.close()
|
||||
|
||||
set_dirty(false)
|
||||
|
||||
# deserialization
|
||||
func load_db() -> int :
|
||||
var file = File.new()
|
||||
file.open(get_db_filepath(), File.READ)
|
||||
var content = file.get_as_text()
|
||||
file.close()
|
||||
var dictionary = JSON.parse(content).result
|
||||
|
||||
# check the signature
|
||||
if(!dictionary.has(gddb_constants.c_gddb_signature)):
|
||||
print("GDDatabase::load_db() - invalid database file")
|
||||
return gddb_types.e_db_invalid_file
|
||||
|
||||
var gddb_signature = dictionary[gddb_constants.c_gddb_signature]
|
||||
if(gddb_signature != gddb_constants.c_gddb_ver):
|
||||
print("GDDatabase::load_db() - invalid database version")
|
||||
return gddb_types.e_db_invalid_ver
|
||||
|
||||
clear()
|
||||
m_db_name = dictionary["db_name"]
|
||||
var tables = dictionary["tables"]
|
||||
for idx in range(0, tables.size()):
|
||||
var table_id = add_table(tables[idx]["table_name"])
|
||||
var table = get_table_by_id(table_id)
|
||||
|
||||
var props_count = tables[idx]["props"].size()
|
||||
if(props_count == 0):
|
||||
continue
|
||||
|
||||
for jdx in range(0, props_count):
|
||||
var prop_type = tables[idx]["props"][jdx]["type"]
|
||||
|
||||
var prop_id = -1
|
||||
if(prop_type == "table"):
|
||||
var table_name = tables[idx]["props"][jdx]["table_name"]
|
||||
prop_id = table.add_table_prop(tables[idx]["props"][jdx]["name"], table_name)
|
||||
else:
|
||||
prop_id = table.add_prop(prop_type.to_int(), tables[idx]["props"][jdx]["name"])
|
||||
|
||||
var prop = table.get_prop_by_id(prop_id)
|
||||
var enable_autoincrement = tables[idx]["props"][jdx]["auto_increment"].to_int()
|
||||
prop.enable_autoincrement(bool(enable_autoincrement))
|
||||
|
||||
var data_count = tables[idx]["data"].size()
|
||||
#print("********* set data to db - begin")
|
||||
for jdx in range(0, data_count / props_count):
|
||||
var row_data = []
|
||||
for kdx in range(0, props_count):
|
||||
var cell_data = tables[idx]["data"][jdx * props_count + kdx]
|
||||
# print("cell_data: " + cell_data)
|
||||
row_data.push_back(cell_data)
|
||||
#print("row_data: " + str(row_data))
|
||||
table.add_row(row_data)
|
||||
#print("********* set data to db - end")
|
||||
|
||||
# link custom data to tables
|
||||
for idx in range(0, m_tables.size()):
|
||||
m_tables[idx].link_tables_props()
|
||||
|
||||
return gddb_types.e_db_valid
|
||||
|
||||
# dumps the database
|
||||
func dump() -> String :
|
||||
var dump_text = "\nDatabase dump. id: " + str(m_db_id) + ", name: " + m_db_name + ", filepath: " + m_db_filepath
|
||||
dump_text += "\n------------------------------------------------------------------------------------\n"
|
||||
|
||||
for idx in range(0, m_tables.size()):
|
||||
dump_text += "\n" + m_tables[idx].dump()
|
||||
|
||||
return dump_text
|
||||
@@ -1,40 +0,0 @@
|
||||
"""
|
||||
GDDBData class
|
||||
"""
|
||||
|
||||
class_name GDDBData
|
||||
|
||||
extends Object
|
||||
|
||||
var m_prop_id : int = -1
|
||||
var m_row_idx : int = -1
|
||||
var m_data : String = ""
|
||||
|
||||
# sets the property id
|
||||
func set_prop_id(prop_id : int) -> void :
|
||||
m_prop_id = prop_id
|
||||
|
||||
# returns the property id
|
||||
func get_prop_id() -> int :
|
||||
return m_prop_id
|
||||
|
||||
# sets the row index
|
||||
func set_row_idx(row_idx : int) -> void :
|
||||
m_row_idx = row_idx
|
||||
|
||||
# returns the row index
|
||||
func get_row_idx() -> int :
|
||||
return m_row_idx
|
||||
|
||||
# sets the data
|
||||
func set_data(data : String) -> void :
|
||||
m_data = data
|
||||
|
||||
# returns the data
|
||||
func get_data() -> String :
|
||||
return m_data
|
||||
|
||||
# dumps the data
|
||||
func dump() -> String :
|
||||
var dump_text = "prop_id: " + str(m_prop_id) + ", row_idx: " + str(m_row_idx) + ", data: " + m_data
|
||||
return dump_text
|
||||
@@ -1,141 +0,0 @@
|
||||
"""
|
||||
GDDBMan class
|
||||
"""
|
||||
|
||||
class_name GDDBMan
|
||||
|
||||
extends Object
|
||||
|
||||
var m_databases = []
|
||||
|
||||
# adds a database
|
||||
func add_database(db_name : String) -> int :
|
||||
if(!can_add_db(db_name)):
|
||||
print("ERROR: GDDBMan::add_database(" + db_name + ") already exists")
|
||||
return gddb_constants.c_invalid_id
|
||||
# print("GDDBMan::add_database(" + db_name + ")")
|
||||
var db_id = generate_new_db_id()
|
||||
var db = load(gddb_constants.c_addon_main_path + "core/database.gd").new()
|
||||
db.set_db_id(db_id)
|
||||
db.set_db_name(db_name)
|
||||
m_databases.push_back(db)
|
||||
return db_id
|
||||
|
||||
# loads a database from a file
|
||||
func load_database(filepath : String) -> int :
|
||||
var db_id = generate_new_db_id()
|
||||
var db = load(gddb_constants.c_addon_main_path + "core/database.gd").new()
|
||||
db.set_db_id(db_id)
|
||||
db.set_db_filepath(filepath)
|
||||
|
||||
if(db.load_db() == gddb_types.e_db_invalid_file):
|
||||
db.free()
|
||||
return gddb_types.e_db_invalid_file
|
||||
|
||||
elif(db.load_db() == gddb_types.e_db_invalid_ver):
|
||||
db.free()
|
||||
return gddb_types.e_db_invalid_ver
|
||||
|
||||
m_databases.push_back(db)
|
||||
return db_id
|
||||
|
||||
# erases a database at index
|
||||
# it does not erase the database file
|
||||
func erase_db_at(idx : int) -> void :
|
||||
if(idx < 0 || idx > m_databases.size() - 1):
|
||||
print("ERROR: GDDBMan::erase_db_at(" + str(idx) + ") - index out of bounds")
|
||||
|
||||
m_databases[idx].clear()
|
||||
m_databases[idx].free()
|
||||
m_databases.remove(idx)
|
||||
|
||||
# erases a database by id
|
||||
# it does not erase the database file
|
||||
func erase_db_by_id(db_id : int) -> void :
|
||||
var db_found = false
|
||||
for idx in range(0, m_databases.size()):
|
||||
if(m_databases[idx].get_db_id() == db_id):
|
||||
m_databases[idx].clear()
|
||||
m_databases[idx].free()
|
||||
m_databases.remove(idx)
|
||||
db_found = true
|
||||
break
|
||||
|
||||
if(!db_found):
|
||||
print("ERROR: GDDBMan::erase_db_by_id(" + str(db_id) + ") - database not found")
|
||||
|
||||
# erases a database by name
|
||||
# it does not erase the database file
|
||||
func erase_db_by_name(db_name : String) -> void :
|
||||
var db_found = false
|
||||
for idx in range(0, m_databases.size()):
|
||||
if(m_databases[idx].get_db_name() == db_name):
|
||||
m_databases[idx].clear()
|
||||
m_databases[idx].free()
|
||||
m_databases.remove(idx)
|
||||
db_found = true
|
||||
break
|
||||
|
||||
if(!db_found):
|
||||
print("ERROR: GDDBMan::erase_db_by_id(" + db_name + ") - database not found")
|
||||
|
||||
# returns the databases count
|
||||
func get_databases_count() -> int :
|
||||
return m_databases.size()
|
||||
|
||||
# returns a database at index
|
||||
func get_db_at(idx : int) -> Object :
|
||||
if(idx < 0 || idx >= m_databases.size()):
|
||||
print("ERROR: GDDBMan::get_db_at(" + str(idx) + ") - invalid index")
|
||||
return null
|
||||
return m_databases[idx]
|
||||
|
||||
# returns a database by an id
|
||||
func get_db_by_id(db_id : int) -> Object :
|
||||
for idx in range(0, m_databases.size()):
|
||||
if(m_databases[idx].get_db_id() == db_id):
|
||||
return m_databases[idx]
|
||||
print("ERROR: GDDBMan::get_db_by_id(" + str(db_id) + ") - invalid id")
|
||||
return null
|
||||
|
||||
# returns a database by a name
|
||||
func get_db_by_name(db_name : String) -> Object :
|
||||
for idx in range(0, m_databases.size()):
|
||||
if(m_databases[idx].get_db_name() == db_name):
|
||||
return m_databases[idx]
|
||||
return null
|
||||
|
||||
# generates a new table id
|
||||
func generate_new_db_id() -> int :
|
||||
if(m_databases.size() == 0):
|
||||
return 0
|
||||
return m_databases[m_databases.size()-1].get_db_id() + 1
|
||||
|
||||
# checks if a database already exists
|
||||
func can_add_db(db_name : String) -> bool :
|
||||
for idx in range(0, m_databases.size()):
|
||||
if(m_databases[idx].get_db_name() == db_name):
|
||||
print("ERROR: Database with name \"" + db_name + "\" already exists")
|
||||
return false
|
||||
return true
|
||||
|
||||
# deletes all databases
|
||||
func clear() -> void :
|
||||
for idx in range(0, m_databases.size()):
|
||||
m_databases[idx].clear()
|
||||
m_databases[idx].free()
|
||||
m_databases.clear()
|
||||
|
||||
# dumps all databases
|
||||
func dump(to_console : bool = false) -> String :
|
||||
var dump_text = "\nDatabase manager - dump"
|
||||
|
||||
dump_text += "\n===================================================================================="
|
||||
for idx in range(0, m_databases.size()):
|
||||
dump_text += m_databases[idx].dump()
|
||||
dump_text += "===================================================================================="
|
||||
|
||||
if(to_console):
|
||||
print(dump_text)
|
||||
|
||||
return dump_text
|
||||
@@ -1,71 +0,0 @@
|
||||
"""
|
||||
GDDBProperty class
|
||||
"""
|
||||
|
||||
class_name GDDBProperty
|
||||
|
||||
extends Object
|
||||
|
||||
var m_prop_id : int = -1
|
||||
var m_prop_type : int = gddb_types.e_prop_type_int
|
||||
var m_custom_type : String = ""
|
||||
var m_prop_name : String = ""
|
||||
|
||||
var m_autoincrement : bool = false
|
||||
|
||||
# sets the property id
|
||||
func set_prop_id(prop_id : int) -> void :
|
||||
m_prop_id = prop_id
|
||||
|
||||
# returns the property id
|
||||
func get_prop_id() -> int :
|
||||
return m_prop_id
|
||||
|
||||
# sets the property type
|
||||
func set_prop_type(prop_type : int) -> void :
|
||||
m_prop_type = prop_type
|
||||
|
||||
# returns the property type
|
||||
func get_prop_type() -> int :
|
||||
return m_prop_type
|
||||
|
||||
# sets the custom type
|
||||
func set_prop_custom_type(prop_type : String) -> void :
|
||||
m_custom_type = prop_type
|
||||
|
||||
# returns the custom type
|
||||
func get_prop_custom_type() -> String :
|
||||
return m_custom_type
|
||||
|
||||
# sets the property name
|
||||
func set_prop_name(prop_name : String) -> void :
|
||||
m_prop_name = prop_name
|
||||
|
||||
# returns the property name
|
||||
func get_prop_name() -> String :
|
||||
return m_prop_name
|
||||
|
||||
# enables or disables the auto increment property
|
||||
func enable_autoincrement(enable : bool) -> void :
|
||||
if(enable && m_prop_type != gddb_types.e_prop_type_int):
|
||||
if(m_prop_type < gddb_types.e_prop_types_count):
|
||||
print("ERROR: autoincrement option can be set to integer data type only. Type is: " + gddb_types.get_data_name(m_prop_type))
|
||||
else:
|
||||
print("ERROR: autoincrement option can be set to integer data type only. Custom type is: " + m_custom_type)
|
||||
return
|
||||
m_autoincrement = enable
|
||||
|
||||
# returns if the property has auto increment
|
||||
func has_autoincrement() -> bool :
|
||||
return m_autoincrement
|
||||
|
||||
# dumps the property
|
||||
func dump() -> String :
|
||||
var dump_text = "prop_id: " + str(m_prop_id) + ", prop_name: " + m_prop_name
|
||||
|
||||
if(m_prop_type <= gddb_types.e_prop_type_resource):
|
||||
dump_text += ", prop_type: " + gddb_globals.get_data_name(m_prop_type)
|
||||
else:
|
||||
dump_text += ", custom_prop_type: " + m_custom_type
|
||||
|
||||
return dump_text
|
||||
@@ -1,574 +0,0 @@
|
||||
"""
|
||||
GDDBTable class
|
||||
"""
|
||||
|
||||
class_name GDDBTable
|
||||
|
||||
extends Object
|
||||
|
||||
var m_table_id : int = gddb_constants.c_invalid_id
|
||||
var m_table_name : String = ""
|
||||
var m_props : Array = []
|
||||
var m_data : Array = []
|
||||
var m_rows_count : int = 0
|
||||
|
||||
var m_parent_database : Object = null
|
||||
|
||||
# sets the table id
|
||||
func set_table_id(table_id : int) -> void :
|
||||
# print("GDDBDTable::set_table_id(" + str(table_id) + ")")
|
||||
m_table_id = table_id
|
||||
|
||||
# returns the table id
|
||||
func get_table_id() -> int :
|
||||
return m_table_id
|
||||
|
||||
# sets the table name
|
||||
func set_table_name(table_name: String) -> void :
|
||||
# print("GDDBDTable::set_table_name(" + table_name + ")")
|
||||
m_table_name = table_name
|
||||
|
||||
# returns the table name
|
||||
func get_table_name() -> String :
|
||||
return m_table_name
|
||||
|
||||
# sets the parent database
|
||||
func set_parent_database(db : Object) -> void :
|
||||
# print("GDDBTable::set_parent_database(" + str(db) + ")")
|
||||
m_parent_database = db
|
||||
|
||||
# returns parent database
|
||||
func get_parent_database() -> Object :
|
||||
return m_parent_database
|
||||
|
||||
# adds a property in the table structure as a base type
|
||||
# returns prop ID
|
||||
func add_prop(prop_type : int, prop_name : String) -> int :
|
||||
var prop_id = generate_new_prop_id()
|
||||
|
||||
# print("GDDBDTable::add_prop(" + str(prop_id) + ", " + str(prop_type) + ", " + prop_name + ")")
|
||||
var prop = load(gddb_constants.c_addon_main_path + "core/db_prop.gd").new()
|
||||
prop.set_prop_id(prop_id)
|
||||
prop.set_prop_type(prop_type)
|
||||
prop.set_prop_name(prop_name)
|
||||
m_props.push_back(prop)
|
||||
|
||||
# adding blank data to all existing rows
|
||||
# TODO: find a way to make this better; this is ugly
|
||||
if(m_data.size() > 0):
|
||||
var new_data_array = []
|
||||
var data_idx = 0
|
||||
var row_idx = 0
|
||||
while(true):
|
||||
var data = m_data[data_idx]
|
||||
row_idx = data.get_row_idx()
|
||||
if(data.get_prop_id() + 1 == prop_id):
|
||||
new_data_array.push_back(data)
|
||||
var new_data = load(gddb_constants.c_addon_main_path + "core/db_data.gd").new()
|
||||
new_data.set_prop_id(prop_id)
|
||||
new_data.set_row_idx(row_idx)
|
||||
|
||||
if(prop_type == gddb_types.e_prop_type_bool):
|
||||
new_data.set_data("0")
|
||||
|
||||
elif(prop_type == gddb_types.e_prop_type_int):
|
||||
if(prop.has_autoincrement()):
|
||||
new_data.set_data(str(m_rows_count+1))
|
||||
else:
|
||||
new_data.set_data("0")
|
||||
|
||||
elif(prop_type == gddb_types.e_prop_type_float):
|
||||
new_data.set_data("0.0")
|
||||
|
||||
elif(prop_type == gddb_types.e_prop_type_string):
|
||||
new_data.set_data("")
|
||||
|
||||
elif(prop_type == gddb_types.e_prop_type_resource):
|
||||
new_data.set_data("res://")
|
||||
|
||||
elif(prop_type >= gddb_types.e_prop_types_count):
|
||||
new_data.set_data(str(-1))
|
||||
|
||||
new_data_array.push_back(new_data)
|
||||
else:
|
||||
new_data_array.push_back(data)
|
||||
|
||||
data_idx += 1
|
||||
if(data_idx >= m_data.size()):
|
||||
break
|
||||
|
||||
m_data.clear()
|
||||
for idx in range(0, new_data_array.size()):
|
||||
m_data.push_back(new_data_array[idx])
|
||||
|
||||
return prop_id
|
||||
|
||||
# adds a property in the table structure as a table type
|
||||
# returns prop ID
|
||||
func add_table_prop(prop_name : String, table_name : String) -> int :
|
||||
# print("GDDBTable::add_table_prop(" + prop_name + ", " + table_name + ")")
|
||||
var prop_id = generate_new_prop_id()
|
||||
|
||||
# print("GDDBDTable::add_prop(" + str(prop_id) + ", " + str(prop_type) + ", " + prop_name + ")")
|
||||
var prop = load(gddb_constants.c_addon_main_path + "core/db_prop.gd").new()
|
||||
prop.set_prop_id(prop_id)
|
||||
prop.set_prop_name(prop_name)
|
||||
prop.set_prop_custom_type(table_name)
|
||||
m_props.push_back(prop)
|
||||
|
||||
return prop_id
|
||||
|
||||
# links custom properties from tables
|
||||
func link_tables_props() -> void :
|
||||
for idx in range(0, m_props.size()):
|
||||
var custom_prop_type = m_props[idx].get_prop_custom_type()
|
||||
if(!custom_prop_type.empty()):
|
||||
var table = m_parent_database.get_table_by_name(custom_prop_type)
|
||||
m_props[idx].set_prop_type(gddb_types.e_prop_types_count + table.get_table_id())
|
||||
m_props[idx].set_prop_custom_type("")
|
||||
|
||||
# edits a property in the table structure
|
||||
func edit_prop(prop_id : int, prop_type : int, prop_name: String) -> void :
|
||||
for idx in range(0, m_props.size()):
|
||||
if(m_props[idx].get_prop_id() == prop_id):
|
||||
m_props[idx].set_prop_type(prop_type)
|
||||
m_props[idx].set_prop_name(prop_name)
|
||||
return
|
||||
|
||||
print("ERROR: GDDBDTable::edit_prop(" + str(prop_id) + ", " + str(prop_type) + ", " + prop_name + ") - property not found")
|
||||
|
||||
# enables or disables autoincrement on a property
|
||||
func enable_prop_autoincrement(prop_id : int, enable : bool) -> void :
|
||||
for idx in range(0, m_props.size()):
|
||||
if(m_props[idx].get_prop_id() == prop_id):
|
||||
m_props[idx].enable_autoincrement(enable)
|
||||
break
|
||||
|
||||
# deletes a property and all the data from the table have the same property
|
||||
func delete_prop(prop_id : int) -> void :
|
||||
# print("db_table::delete_prop(" + str(prop_id) + ")")
|
||||
var prop_found = false
|
||||
for idx in range(0, m_props.size()):
|
||||
if(m_props[idx].get_prop_id() == prop_id):
|
||||
# print("Removing prop with id " + str(prop_id))
|
||||
m_props[idx].free()
|
||||
m_props.remove(idx)
|
||||
prop_found = true
|
||||
break
|
||||
|
||||
if(!prop_found):
|
||||
print("ERROR: GDDBDTable::delete_prop( " + str(prop_id) + " ) - property not found !")
|
||||
return
|
||||
|
||||
# remove the data
|
||||
# this is very ugly, but I can't erase a subarray from an array in GDscript :(
|
||||
# backup what needs to be saved only
|
||||
var tmp_data = []
|
||||
for idx in range(0, m_data.size()):
|
||||
if(m_data[idx].get_prop_id() == prop_id):
|
||||
continue
|
||||
tmp_data.push_back(m_data[idx])
|
||||
# clear and restore data
|
||||
m_data.clear()
|
||||
for idx in range(0, tmp_data.size()):
|
||||
m_data.push_back(tmp_data[idx])
|
||||
|
||||
# generates a new table id
|
||||
func generate_new_prop_id() -> int :
|
||||
if(m_props.size() == 0):
|
||||
return 0
|
||||
|
||||
return m_props[m_props.size()-1].get_prop_id() + 1
|
||||
|
||||
# returns the properties count
|
||||
func get_props_count() -> int :
|
||||
return m_props.size()
|
||||
|
||||
# returns the property at index or null if the index is out of bounds
|
||||
func get_prop_at(idx : int) -> Object :
|
||||
if(idx < 0 || idx >= m_props.size()):
|
||||
print("ERROR: GDDBDTable::get_prop_id( " + str(idx) + " ) - index out of bounds; max properties: " + str(m_props.size()))
|
||||
return null
|
||||
|
||||
return m_props[idx]
|
||||
|
||||
# returns a property by id or null if the id is not found
|
||||
func get_prop_by_id(prop_id : int) -> Object :
|
||||
for idx in range(0, m_props.size()):
|
||||
if(m_props[idx].get_prop_id() == prop_id):
|
||||
return m_props[idx]
|
||||
|
||||
print("ERROR: GDDBDTable::get_prop_by_id(" + str(prop_id) + ") - property with id not found")
|
||||
return null
|
||||
|
||||
# returns a property by name
|
||||
func get_prop_by_name(pror_name : String) -> Object :
|
||||
for idx in range(0, m_props.size()):
|
||||
if(m_props[idx].get_prop_name() == pror_name):
|
||||
return m_props[idx]
|
||||
|
||||
print("ERROR: GDDBDTable::get_prop_by_name(" + str(pror_name) + ") - property with name not found")
|
||||
return null
|
||||
|
||||
# adds a row with blank data
|
||||
func add_blank_row() -> void :
|
||||
# print("GDDBTable::add_blank_row()")
|
||||
var prop_type = gddb_types.e_prop_type_bool
|
||||
|
||||
for idx in range(0, m_props.size()):
|
||||
var data = load(gddb_constants.c_addon_main_path + "core/db_data.gd").new()
|
||||
data.set_prop_id(m_props[idx].get_prop_id())
|
||||
data.set_row_idx(m_rows_count)
|
||||
|
||||
prop_type = m_props[idx].get_prop_type()
|
||||
|
||||
if(prop_type == gddb_types.e_prop_type_bool):
|
||||
data.set_data("0")
|
||||
|
||||
elif(prop_type == gddb_types.e_prop_type_int):
|
||||
if(m_props[idx].has_autoincrement()):
|
||||
data.set_data(str(m_rows_count+1))
|
||||
else:
|
||||
data.set_data("0")
|
||||
|
||||
elif(prop_type == gddb_types.e_prop_type_float):
|
||||
data.set_data("0.0")
|
||||
|
||||
elif(prop_type == gddb_types.e_prop_type_string):
|
||||
data.set_data("")
|
||||
|
||||
elif(prop_type == gddb_types.e_prop_type_resource):
|
||||
data.set_data("res://")
|
||||
|
||||
elif(prop_type >= gddb_types.e_prop_types_count):
|
||||
data.set_data(str(-1))
|
||||
|
||||
m_data.push_back(data)
|
||||
|
||||
m_rows_count += 1
|
||||
|
||||
# adds a row with data
|
||||
func add_row(data_array : Array) -> void :
|
||||
if(data_array.size() != m_props.size()):
|
||||
print("ERROR: GDDBDTable::add_row( " + str(data_array) + " ) - cannot add row; properties count = " + str(m_props.size()) + " and data size = " + str(data_array.size()))
|
||||
return
|
||||
|
||||
var prop_type = gddb_types.e_prop_type_bool
|
||||
var the_data = ""
|
||||
|
||||
for idx in range(0, m_props.size()):
|
||||
var data = load(gddb_constants.c_addon_main_path + "core/db_data.gd").new()
|
||||
# print("adding data: [" + str(m_props[idx].get_prop_id()) + ", " + data_array[idx] + "]")
|
||||
# print("setting prop id: " + str(m_props[idx].get_prop_id()))
|
||||
|
||||
data.set_prop_id(m_props[idx].get_prop_id())
|
||||
data.set_row_idx(m_rows_count)
|
||||
|
||||
# ignore data if the property has autoincrement option
|
||||
if(m_props[idx].has_autoincrement()):
|
||||
data.set_data(str(m_rows_count+1))
|
||||
m_data.push_back(data)
|
||||
continue
|
||||
|
||||
prop_type = m_props[idx].get_prop_type()
|
||||
the_data = data_array[idx]
|
||||
|
||||
if(prop_type == gddb_types.e_prop_type_bool):
|
||||
data.set_data(str(the_data))
|
||||
elif(prop_type == gddb_types.e_prop_type_int):
|
||||
data.set_data(str(the_data))
|
||||
elif(prop_type == gddb_types.e_prop_type_float):
|
||||
data.set_data(str(the_data))
|
||||
elif(prop_type == gddb_types.e_prop_type_string):
|
||||
data.set_data(gddb_globals.handle_string(the_data))
|
||||
elif(prop_type == gddb_types.e_prop_type_resource):
|
||||
data.set_data(the_data)
|
||||
else:
|
||||
print("ERROR: data type doesn't exist - " + str(m_props[idx].get_prop_type()))
|
||||
|
||||
m_data.push_back(data)
|
||||
|
||||
m_rows_count += 1
|
||||
|
||||
# removes a row
|
||||
func remove_row(row_idx : int) -> void :
|
||||
for idx in range(m_data.size()-1, 0, -1):
|
||||
if(m_data[idx].get_row_idx() == row_idx):
|
||||
m_data[idx].remove(idx)
|
||||
m_rows_count -= 1
|
||||
|
||||
# returns the rows count
|
||||
func get_rows_count() -> int :
|
||||
return m_rows_count
|
||||
|
||||
# edits the data
|
||||
func edit_data(prop_id : int, row_idx : int, data : String) -> void :
|
||||
# print("#1: GDDBTable::edit_data( " + str(prop_id) + ", " + str(row_idx) + ", " + data + " )")
|
||||
for idx in range(0, m_data.size()):
|
||||
# print("checking ( " + str(m_data[idx].get_row_idx()) + ", " + str(m_data[idx].get_prop_id()) + " )")
|
||||
if(m_data[idx].get_row_idx() == row_idx && m_data[idx].get_prop_id() == prop_id):
|
||||
# print("#2: GDDBTable::edit_data( " + str(prop_id) + ", " + str(row_idx) + ", " + data + " )")
|
||||
m_data[idx].set_data(data)
|
||||
return
|
||||
|
||||
print("ERROR: GDDBDTable::edit_data(" + str(prop_id) + ", " + str(row_idx) + ", " + data + ") - can't find data to edit")
|
||||
|
||||
# edits the data
|
||||
func edit_data_by_prop_name(prop_name : String, row_idx : int, data : String) -> void :
|
||||
# print("#1: GDDBTable::edit_data( " + str(prop_id) + ", " + str(row_idx) + ", " + data + " )")
|
||||
|
||||
var prop_id = get_prop_by_name(prop_name).get_prop_id()
|
||||
edit_data(prop_id, row_idx, data)
|
||||
|
||||
# returns data count
|
||||
func get_data_size() -> int :
|
||||
return m_data.size()
|
||||
|
||||
# returns all data
|
||||
func get_all_data() -> Array :
|
||||
return m_data
|
||||
|
||||
# returns the data at index
|
||||
func get_data_at(idx : int) -> String :
|
||||
if(idx < 0 || idx >= m_data.size()):
|
||||
print("ERROR: GDDBDTable::get_data_at( " + str(idx) + ") - max data size: " + str(m_data.size()))
|
||||
return ""
|
||||
|
||||
return m_data[idx].get_data()
|
||||
|
||||
# returns a dictionary containing the data at index
|
||||
func get_dictionary_at(idx : int) -> Dictionary :
|
||||
var dict = {}
|
||||
|
||||
if(idx < 0 || idx >= m_data.size()):
|
||||
print("ERROR: GDDBDTable::get_data_at( " + str(idx) + ") - max data size: " + str(m_data.size()))
|
||||
return dict
|
||||
|
||||
var prop_idx = idx % m_props.size()
|
||||
var data_prop_name = m_props[prop_idx].get_prop_name()
|
||||
dict[data_prop_name] = m_data[idx].get_data()
|
||||
|
||||
return dict
|
||||
|
||||
# returns the data by a property id and a row index
|
||||
func get_data(prop_id : int, row_idx : int) -> String :
|
||||
for idx in range(m_data.size()-1, 0, -1):
|
||||
if(m_data[idx].get_row_idx() == row_idx && m_data[idx].get_prop_id() == prop_id):
|
||||
return m_data[idx].get_data()
|
||||
|
||||
print("ERROR: GDDBDTable::get_data(" + str(prop_id) + ", " + str(row_idx) + ")")
|
||||
return ""
|
||||
|
||||
# returns a dictionary containing the data by a property id and a row index
|
||||
func get_dictionary(prop_id : int, row_idx : int) -> Dictionary :
|
||||
var dict = {}
|
||||
|
||||
for idx in range(m_data.size()-1, 0, -1):
|
||||
if(m_data[idx].get_row_idx() == row_idx && m_data[idx].get_prop_id() == prop_id):
|
||||
var prop = get_prop_by_id(prop_id)
|
||||
var data_prop_name = prop.get_prop_name()
|
||||
dict[data_prop_name] = m_data[idx].get_data()
|
||||
return dict
|
||||
|
||||
print("ERROR: GDDBDTable::get_data(" + str(prop_id) + ", " + str(row_idx) + ")")
|
||||
return dict
|
||||
|
||||
# returns an array of data at row index
|
||||
func get_data_at_row_idx(row_idx : int) -> Array :
|
||||
var data = []
|
||||
for idx in range(0, m_data.size()):
|
||||
if(m_data[idx].get_row_idx() == row_idx):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
if(data.size() == -1):
|
||||
print("ERROR: GDDBDTable::get_data_at_row_idx(" + str(row_idx) + ") - invalid row index")
|
||||
|
||||
return data
|
||||
|
||||
# returns a dictionary of data at row index
|
||||
func get_dictionary_at_row_idx(row_idx : int) -> Dictionary :
|
||||
var dict = {}
|
||||
|
||||
var prop_idx = 0
|
||||
for idx in range(0, m_data.size()):
|
||||
if(m_data[idx].get_row_idx() == row_idx):
|
||||
var data_prop_name = m_props[prop_idx].get_prop_name()
|
||||
dict[data_prop_name] = m_data[idx].get_data()
|
||||
prop_idx += 1
|
||||
|
||||
if(dict.empty()):
|
||||
print("ERROR: GDDBDTable::get_data_at_row_idx(" + str(row_idx) + ") - invalid row index")
|
||||
|
||||
return dict
|
||||
|
||||
# returns an array of data filtered by property id
|
||||
func get_data_by_prop_id(prop_id : int, data_filter : int = gddb_types.e_data_filter_equal) -> Array :
|
||||
var data = []
|
||||
|
||||
if(data_filter < gddb_types.e_data_filter_equal || data_filter >= gddb_types.e_data_filter_gequal):
|
||||
print("ERROR: cannot process filter " + str(data_filter))
|
||||
return data
|
||||
|
||||
for idx in range(0, m_data.size()):
|
||||
if(data_filter == gddb_types.e_data_filter_equal):
|
||||
if(m_data[idx].get_prop_id() == prop_id):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_not_equal):
|
||||
if(m_data[idx].get_prop_id() != prop_id):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_less):
|
||||
if(m_data[idx].get_prop_id() < prop_id):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_greater):
|
||||
if(m_data[idx].get_prop_id() > prop_id):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_lequal):
|
||||
if(m_data[idx].get_prop_id() <= prop_id):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_gequal):
|
||||
if(m_data[idx].get_prop_id() >= prop_id):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
if(data.size() == 0):
|
||||
print("ERROR: GDDBDTable::get_data_by_prop_id(" + str(prop_id) + ", " + gddb_globals.get_data_filter_name(data_filter) + ") - filtered data not found")
|
||||
|
||||
return data
|
||||
|
||||
# returns an array of data by property name
|
||||
func get_data_by_prop_name(prop_name : String) -> Array :
|
||||
var prop_id = -1
|
||||
for idx in range(0, m_props.size()):
|
||||
if(m_props[idx].get_prop_name() == prop_name):
|
||||
prop_id = m_props[idx].get_prop_id()
|
||||
break
|
||||
|
||||
if(prop_id == -1):
|
||||
print("ERROR: GDDBDTable::get_data_by_prop_name(" + prop_name + ") - property not found")
|
||||
return []
|
||||
|
||||
return get_data_by_prop_id(prop_id)
|
||||
|
||||
# returns an array of data filtered by data
|
||||
# filters "<", ">", "<=" and ">=" are working for integer and float data types
|
||||
func get_data_by_data(data_value : String, data_filter : int = gddb_types.e_data_filter_equal) -> Array :
|
||||
var data = []
|
||||
|
||||
if(data_filter < gddb_types.e_data_filter_equal || data_filter >= gddb_types.e_data_filter_gequal):
|
||||
print("ERROR: cannot process filter " + str(data_filter))
|
||||
return data
|
||||
|
||||
for idx in range(0, m_data.size()):
|
||||
if(data_filter == gddb_types.e_data_filter_equal):
|
||||
if(m_data[idx].get_data() == data_value):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_not_equal):
|
||||
if(m_data[idx].get_data() != data_value):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_less):
|
||||
if(m_props[idx].get_prop_type() < gddb_types.e_prop_type_resource):
|
||||
if(m_data[idx].get_data() < data_value):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_greater):
|
||||
if(m_props[idx].get_prop_type() < gddb_types.e_prop_type_resource):
|
||||
if(m_data[idx].get_data() > data_value):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_lequal):
|
||||
if(m_props[idx].get_prop_type() < gddb_types.e_prop_type_resource):
|
||||
if(m_data[idx].get_data() <= data_value):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
elif(data_filter == gddb_types.e_data_filter_gequal):
|
||||
if(m_props[idx].get_prop_type() < gddb_types.e_prop_type_resource):
|
||||
if(m_data[idx].get_data() >= data_value):
|
||||
data.push_back(m_data[idx])
|
||||
|
||||
if(data.size() == 0):
|
||||
print("ERROR: GDDBDTable::get_data_by_data(" + data_value + ", " + gddb_globals.get_data_filter_name(data_filter) + ") - filtered data not found")
|
||||
|
||||
return data
|
||||
|
||||
# returns an array of data by a property name and a data value
|
||||
# similar to: select * from users where user_id = 1
|
||||
func get_data_by_prop_name_and_data(prop_name : String, data_value : String) -> Array :
|
||||
var the_array = []
|
||||
|
||||
var prop_idx = -1
|
||||
for idx in range(0, m_props.size()):
|
||||
if(m_props[idx].get_prop_name() == prop_name):
|
||||
prop_idx = idx
|
||||
break
|
||||
|
||||
for idx in range(0, m_rows_count):
|
||||
var row_data = get_data_at_row_idx(idx)
|
||||
# print("Comparing row: " + row_data[0].get_data() + ", " + row_data[1].get_data() + ", " + row_data[2].get_data() + ", " + row_data[3].get_data() + ", " + row_data[4].get_data())
|
||||
if(row_data[prop_idx].get_data() == data_value):
|
||||
var dict = get_dictionary_at_row_idx(idx)
|
||||
the_array.push_back(row_data)
|
||||
|
||||
return the_array
|
||||
|
||||
# returns a dictionary of data by a property name and a data value
|
||||
# similar to: select * from users where user_id = 1
|
||||
func get_dictionary_by_prop_name_and_data(prop_name : String, data_value : String) -> Array :
|
||||
var the_array = []
|
||||
|
||||
var prop_idx = -1
|
||||
for idx in range(0, m_props.size()):
|
||||
if(m_props[idx].get_prop_name() == prop_name):
|
||||
prop_idx = idx
|
||||
break
|
||||
|
||||
for idx in range(0, m_rows_count):
|
||||
var row_data = get_data_at_row_idx(idx)
|
||||
# print("Comparing row: " + row_data[0].get_data() + ", " + row_data[1].get_data() + ", " + row_data[2].get_data() + ", " + row_data[3].get_data() + ", " + row_data[4].get_data())
|
||||
if(row_data[prop_idx].get_data() == data_value):
|
||||
var dict = get_dictionary_at_row_idx(idx)
|
||||
the_array.push_back(get_dictionary_at_row_idx(idx))
|
||||
|
||||
return the_array
|
||||
|
||||
# clears the table's structure and data
|
||||
func clear() -> void :
|
||||
# clear data
|
||||
clear_data()
|
||||
|
||||
# clear properties
|
||||
for idx in range(0, m_props.size()):
|
||||
m_props[idx].free()
|
||||
m_props.clear()
|
||||
|
||||
# clears the table's data
|
||||
func clear_data() -> void :
|
||||
for idx in range(0, m_data.size()):
|
||||
m_data[idx].free()
|
||||
m_data.clear()
|
||||
m_rows_count = 0
|
||||
|
||||
# dumps the table
|
||||
func dump() -> String :
|
||||
var dump_text = "Table dump. id: " + str(m_table_id) + ", name: " + m_table_name + ", props_count: " + str(m_props.size()) + ", rows_count: " + str(m_rows_count)
|
||||
dump_text += "\n------------------------------------------------------------------------------------\nProperties:"
|
||||
|
||||
for idx in range(0, m_props.size()):
|
||||
dump_text += "\n" + m_props[idx].dump()
|
||||
|
||||
dump_text += "\n------------------------------------------------------------------------------------\nData:\n"
|
||||
|
||||
for idx in range(0, m_rows_count):
|
||||
var tmp_text = "row_idx: " + "%" + str(gddb_globals.get_digits_count(m_rows_count)) + "d"
|
||||
dump_text += tmp_text % idx
|
||||
var row = get_data_at_row_idx(idx)
|
||||
for jdx in range(0, row.size()):
|
||||
dump_text += " | " + row[jdx].get_data()
|
||||
dump_text += "\n"
|
||||
|
||||
return dump_text
|
||||
@@ -1,59 +0,0 @@
|
||||
"""
|
||||
class GDDBDataLabel
|
||||
"""
|
||||
|
||||
class_name GDDBDataLabel
|
||||
|
||||
tool
|
||||
extends Label
|
||||
|
||||
signal resize_property
|
||||
|
||||
var m_prop_id : int = gddb_constants.c_invalid_id
|
||||
var m_prop_type : int = gddb_constants.c_invalid_id
|
||||
|
||||
var m_mouse_pos_pressed : Vector2 = Vector2()
|
||||
var m_mouse_pressed : bool = false
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
set_custom_minimum_size(Vector2(150.0, 24.0))
|
||||
|
||||
# called when the node gets an input
|
||||
func _input(event : InputEvent) -> void :
|
||||
if(!gddb_globals.is_interface_active()):
|
||||
return
|
||||
|
||||
var evLocal = $resize_ctrl.make_input_local(event)
|
||||
|
||||
if event is InputEventMouseButton :
|
||||
if(event.button_index == BUTTON_LEFT):
|
||||
if(event.pressed):
|
||||
var rect = Rect2(Vector2(0, 0), $resize_ctrl.get_size())
|
||||
var inside = rect.has_point(evLocal.position)
|
||||
if(inside):
|
||||
m_mouse_pressed = true
|
||||
m_mouse_pos_pressed = evLocal.position
|
||||
else:
|
||||
m_mouse_pressed = false
|
||||
|
||||
elif event is InputEventMouseMotion :
|
||||
if(m_mouse_pressed):
|
||||
var diff_x = evLocal.position.x - m_mouse_pos_pressed.x
|
||||
emit_signal("resize_property", m_prop_id, diff_x)
|
||||
|
||||
# sets property id
|
||||
func set_prop_id(id : int) -> void:
|
||||
m_prop_id = id
|
||||
|
||||
# returns property id
|
||||
func get_prop_id() -> int:
|
||||
return m_prop_id
|
||||
|
||||
# sets property type
|
||||
func set_prop_type(prop_type : int) -> void :
|
||||
m_prop_type = prop_type
|
||||
|
||||
# returns property type
|
||||
func get_prop_type() -> int :
|
||||
return m_prop_type
|
||||
@@ -1,44 +0,0 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/data_label.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_18.tres" type="DynamicFont" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/gui.png" type="Texture" id=3]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/debug.png" type="Texture" id=4]
|
||||
|
||||
[node name="lbl" type="Label"]
|
||||
anchor_right = 0.167
|
||||
margin_right = -0.300018
|
||||
margin_bottom = 11.52
|
||||
rect_min_size = Vector2( 150, 32 )
|
||||
mouse_filter = 0
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
text = "ID"
|
||||
valign = 1
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ 24.0 ],
|
||||
"_edit_use_anchors_": true
|
||||
}
|
||||
|
||||
[node name="dbg" type="NinePatchRect" parent="."]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
texture = ExtResource( 4 )
|
||||
region_rect = Rect2( 86, 26, 10, 10 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="resize_ctrl" type="NinePatchRect" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -3.0
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 10
|
||||
texture = ExtResource( 3 )
|
||||
region_rect = Rect2( 80, 12, 24, 24 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
"""
|
||||
class GDDBEditor
|
||||
"""
|
||||
|
||||
class_name GDDBEditor
|
||||
|
||||
tool
|
||||
extends Tabs
|
||||
|
||||
var m_name = ""
|
||||
var m_database = null
|
||||
|
||||
var m_filepath = ""
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void :
|
||||
set_tab_align(Tabs.ALIGN_LEFT)
|
||||
set_tab_close_display_policy(Tabs.CLOSE_BUTTON_SHOW_ALWAYS)
|
||||
|
||||
$tables_list.connect("resize_tables_list", self, "on_resize_the_table_list")
|
||||
$tables_list.connect("add_table", self, "on_add_table")
|
||||
$tables_list.connect("edit_table_name", self, "on_edit_table")
|
||||
$tables_list.connect("delete_table", self, "on_delete_table")
|
||||
$tables_list.connect("select_table", self, "on_select_table")
|
||||
|
||||
$table_editor.connect("set_dirty", self, "on_set_dirty")
|
||||
|
||||
$delete_table_dlg.connect("delete_table", self, "on_confirm_delete_table")
|
||||
|
||||
$new_table_dlg.connect("cancel_dialog", self, "on_close_new_table_dlg")
|
||||
$new_table_dlg.get_close_button().connect("pressed", self, "on_close_new_table_dlg")
|
||||
|
||||
$error_dlg.connect("confirmed", self, "on_retry_create_table")
|
||||
|
||||
# resizing the tables list
|
||||
func on_resize_the_table_list(diff_x : float) -> void :
|
||||
var size = $tables_list.get_size()
|
||||
var min_size = $tables_list.get_custom_minimum_size()
|
||||
size.x += diff_x
|
||||
|
||||
if(size.x < min_size.x):
|
||||
return
|
||||
|
||||
if(size.x > gddb_constants.c_max_tables_list_width):
|
||||
return
|
||||
|
||||
$tables_list.resize_content(size)
|
||||
|
||||
var pos = $table_editor.get_position()
|
||||
size = $table_editor.get_size()
|
||||
pos.x += diff_x
|
||||
size.x -= diff_x
|
||||
$table_editor.set_position(pos)
|
||||
$table_editor.set_size(size)
|
||||
|
||||
# overrides the member from base class
|
||||
func set_name(ctrl_name) -> void :
|
||||
m_name = ctrl_name
|
||||
.set_name(ctrl_name)
|
||||
|
||||
# sets the database; for easy access
|
||||
func set_database(db) -> void :
|
||||
# print("GDDBEditor::set_database(" + db.get_db_name() + ") to " + get_name())
|
||||
m_database = db
|
||||
set_dirty(true)
|
||||
|
||||
var tables_count = db.get_tables_count()
|
||||
|
||||
$table_editor.hide()
|
||||
|
||||
for idx in range(0, tables_count):
|
||||
var table = db.get_table_at(idx)
|
||||
$tables_list.create_table(table, idx == 0)
|
||||
if(idx == 0):
|
||||
$table_editor.set_table(table)
|
||||
$table_editor.link_props()
|
||||
$table_editor.show()
|
||||
|
||||
# returns the database id
|
||||
func get_db_id() -> int :
|
||||
if(null == m_database):
|
||||
return gddb_constants.c_invalid_id
|
||||
return m_database.get_db_id()
|
||||
|
||||
# returns the database name
|
||||
func get_db_name() -> String :
|
||||
if(null == m_database):
|
||||
return ""
|
||||
return m_database.get_db_name()
|
||||
|
||||
# sets the database to be dirty; should be saved
|
||||
func set_dirty(dirty) -> void :
|
||||
if(dirty):
|
||||
var title = m_name + "*"
|
||||
.set_name(title)
|
||||
else:
|
||||
.set_name(m_name)
|
||||
|
||||
# called when the user presses the "add_table" button from the "tables_list/tables_header"
|
||||
func on_add_table() -> void :
|
||||
# print("GDDBEditor::on_add_table()")
|
||||
$new_table_dlg.set_dld_type(gddb_types.e_new_dlg_type_new)
|
||||
$new_table_dlg.set_table_id(gddb_constants.c_invalid_id)
|
||||
$new_table_dlg.set_init_name("")
|
||||
$new_table_dlg.connect("create_new_table", self, "on_create_table")
|
||||
$new_table_dlg.popup_centered()
|
||||
|
||||
# called when the user accepts the name of the table in the "new_table_dlg"
|
||||
func on_create_table(table_name : String) -> void :
|
||||
# print("GDDBEditor::on_create_table(" + table_name + ")")
|
||||
$new_table_dlg.disconnect("create_new_table", self, "on_create_table")
|
||||
var table_id = m_database.add_table(table_name)
|
||||
if(table_id == gddb_constants.c_invalid_id):
|
||||
$error_dlg.set_text("Table with the name \"" + table_name + "\" already exists" )
|
||||
$error_dlg.popup_centered()
|
||||
return
|
||||
var table = m_database.get_table_by_id(table_id)
|
||||
$tables_list.create_table(table)
|
||||
$table_editor.set_table(table)
|
||||
$table_editor.show()
|
||||
m_database.set_dirty(true)
|
||||
set_dirty(true)
|
||||
|
||||
# called when the user retryes to create a table (changed the name)
|
||||
func on_retry_create_table() -> void :
|
||||
$new_table_dlg.set_init_name("")
|
||||
$new_table_dlg.popup_centered()
|
||||
|
||||
# called when the user presses the "edit_table_name" from the "tables/list/table"
|
||||
func on_edit_table(table_id : int, table_name : String) -> void :
|
||||
# print("GDDBEditor::on_edit_table(" + str(table_id) + ", " + table_name + ")")
|
||||
$new_table_dlg.set_dld_type(gddb_types.e_new_dlg_type_edit)
|
||||
$new_table_dlg.set_table_id(table_id)
|
||||
$new_table_dlg.set_init_name(table_name)
|
||||
$new_table_dlg.connect("create_new_table", self, "on_table_name_edited")
|
||||
$new_table_dlg.popup_centered()
|
||||
|
||||
# gets called when canceling the new_table_dlg
|
||||
func on_close_new_table_dlg() -> void :
|
||||
# print("GDDBEditor::on_close_new_table_dlg()")
|
||||
var dlg_type = $new_table_dlg.get_dlg_type()
|
||||
if(dlg_type == gddb_types.e_new_dlg_type_new):
|
||||
$new_table_dlg.disconnect("create_new_table", self, "on_create_table")
|
||||
elif(dlg_type == gddb_types.e_new_dlg_type_edit):
|
||||
$new_table_dlg.disconnect("create_new_table", self, "on_table_name_edited")
|
||||
|
||||
# called when the user presses the "delete_table" from the "tables/list/table"
|
||||
func on_delete_table(table_id : int) -> void :
|
||||
# print("GDDBEditor::on_delete_table(" + str(table_id) + ")")
|
||||
var table = m_database.get_table_by_id(table_id)
|
||||
$delete_table_dlg.set_table_id(table_id)
|
||||
$delete_table_dlg.set_table_name(table.get_table_name())
|
||||
$delete_table_dlg.popup_centered()
|
||||
|
||||
# called when the user accepts the name of the table in the "new_table_dlg"
|
||||
func on_table_name_edited(table_name : String) -> void :
|
||||
# print("GDDBEditor::on_table_name_edited(" + table_name + ")")
|
||||
$new_table_dlg.disconnect("create_new_table", self, "on_table_name_edited")
|
||||
var table_id = $new_table_dlg.get_table_id()
|
||||
if(!m_database.edit_table_name(table_name, table_id)):
|
||||
$error_dlg.set_text("Table with the name \"" + table_name + "\" already exists" )
|
||||
$error_dlg.popup_centered()
|
||||
return
|
||||
# print("GDDBEditor::on_table_name_edited(" + str(table_id) + ", " + table_name + ")")
|
||||
$tables_list.edit_table_name(table_id, table_name)
|
||||
m_database.set_dirty(true)
|
||||
set_dirty(true)
|
||||
|
||||
# called when the user confirms to delete a table
|
||||
func on_confirm_delete_table() -> void :
|
||||
# print("GDDBEditor::on_confirm_delete_table()")
|
||||
var table_id = $delete_table_dlg.get_table_id()
|
||||
var selected_table = $tables_list.get_selected_item()
|
||||
if(null == selected_table):
|
||||
return
|
||||
var selected_table_id = selected_table.get_table_id()
|
||||
m_database.delete_table_by_id(table_id)
|
||||
$tables_list.delete_table(table_id)
|
||||
if(selected_table_id == table_id):
|
||||
$tables_list.select_item_at(0)
|
||||
var table = m_database.get_table_at(0)
|
||||
$table_editor.set_table(table)
|
||||
|
||||
m_database.set_dirty(true)
|
||||
set_dirty(true)
|
||||
|
||||
# called when the user selects a table from the table_list
|
||||
func on_select_table(table_id : int) -> void :
|
||||
var table = m_database.get_table_by_id(table_id)
|
||||
if(null != table):
|
||||
$table_editor.set_table(table)
|
||||
$table_editor.link_props()
|
||||
|
||||
# saves current database
|
||||
func save_database() -> void:
|
||||
m_database.save_db()
|
||||
set_dirty(false)
|
||||
|
||||
# returns true if the database can be saved, otherwise false
|
||||
func can_save_database() -> bool:
|
||||
return !m_database.get_db_filepath().empty()
|
||||
|
||||
# sets the database's path
|
||||
func set_database_filepath(filepath : String) -> void:
|
||||
m_database.set_db_filepath(filepath)
|
||||
|
||||
# called when a table is modified
|
||||
func on_set_dirty() -> void:
|
||||
m_database.set_dirty(true)
|
||||
set_dirty(true)
|
||||
@@ -1,40 +0,0 @@
|
||||
[gd_scene load_steps=8 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/db_editor.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/tables_list.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/new_table_dlg.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://addons/godot_db_manager/table_editor.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/error_dlg.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/delete_table_dlg.tscn" type="PackedScene" id=6]
|
||||
[ext_resource path="res://addons/godot_db_manager/debug/dbg.tscn" type="PackedScene" id=7]
|
||||
|
||||
[node name="db_editor" type="Tabs"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
tab_align = 0
|
||||
tab_close_display_policy = 2
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": true,
|
||||
"_edit_vertical_guides_": [ 170.0, 900.0 ]
|
||||
}
|
||||
|
||||
[node name="tables_list" parent="." instance=ExtResource( 2 )]
|
||||
anchor_right = 0.0
|
||||
margin_right = 170.0
|
||||
rect_min_size = Vector2( 180, 30 )
|
||||
|
||||
[node name="table_editor" parent="." instance=ExtResource( 4 )]
|
||||
margin_left = 181.0
|
||||
|
||||
[node name="dbg" parent="." instance=ExtResource( 7 )]
|
||||
visible = false
|
||||
|
||||
[node name="new_table_dlg" parent="." instance=ExtResource( 3 )]
|
||||
visible = false
|
||||
|
||||
[node name="delete_table_dlg" parent="." instance=ExtResource( 6 )]
|
||||
visible = false
|
||||
|
||||
[node name="error_dlg" parent="." instance=ExtResource( 5 )]
|
||||
visible = false
|
||||
@@ -1,155 +0,0 @@
|
||||
"""
|
||||
class GDDBInterface
|
||||
"""
|
||||
|
||||
class_name GDDBInterface
|
||||
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var m_db_manager = null
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
# init db_manager
|
||||
m_db_manager = load(gddb_constants.c_addon_main_path + "core/db_man.gd").new()
|
||||
|
||||
# menu connections
|
||||
$dlg/menu.connect("new_database", self, "on_menu_new_database")
|
||||
$dlg/menu.connect("load_database", self, "on_menu_load_database")
|
||||
$dlg/menu.connect("save_database", self, "on_menu_save_database")
|
||||
$dlg/menu.connect("save_database_as", self, "on_menu_save_database_as")
|
||||
|
||||
# dialod notifications
|
||||
$dlg.connect("about_to_show", self, "on_about_to_show")
|
||||
$dlg.get_close_button().connect("pressed", self, "on_close")
|
||||
|
||||
# new database connections
|
||||
$dlg/new_db_dlg.connect("create_new_db", self, "on_new_database")
|
||||
|
||||
# save / load connections
|
||||
$dlg/load_db_dlg.connect("file_selected", self, "on_file_selected")
|
||||
|
||||
# Called when the node is about to be shown.
|
||||
func on_about_to_show() -> void :
|
||||
gddb_globals.set_interface_active(true)
|
||||
|
||||
func on_close() -> void :
|
||||
gddb_globals.set_interface_active(false)
|
||||
|
||||
# called when creating a new database from the menu
|
||||
func on_menu_new_database() -> void:
|
||||
$dlg/new_db_dlg/v_layout/db_info/db_edt.set_text("")
|
||||
$dlg/new_db_dlg.popup_centered()
|
||||
|
||||
# called when loading a database from the menu
|
||||
func on_menu_load_database() -> void:
|
||||
$dlg/load_db_dlg.set_mode(FileDialog.MODE_OPEN_FILE)
|
||||
$dlg/load_db_dlg.set_title("Load Database ...")
|
||||
$dlg/load_db_dlg.set_current_file("")
|
||||
$dlg/load_db_dlg.popup_centered()
|
||||
|
||||
# called when saving a database from the menu
|
||||
func on_menu_save_database() -> void:
|
||||
# print("on_menu_save_database")
|
||||
var currnet_tab = $dlg/databases.get_current_tab_control()
|
||||
if(currnet_tab.can_save_database()):
|
||||
currnet_tab.save_database()
|
||||
else:
|
||||
on_menu_save_database_as()
|
||||
|
||||
# called when saving a database as another from the menu
|
||||
func on_menu_save_database_as():
|
||||
# print("on_menu_save_database_as")
|
||||
$dlg/load_db_dlg.set_mode(FileDialog.MODE_SAVE_FILE)
|
||||
$dlg/load_db_dlg.set_title("Save Database As ...")
|
||||
|
||||
var currnet_tab = $dlg/databases.get_current_tab_control()
|
||||
|
||||
$dlg/load_db_dlg.set_current_file(currnet_tab.get_db_name())
|
||||
$dlg/load_db_dlg.popup_centered()
|
||||
|
||||
# called when adding a new database
|
||||
func on_new_database(db_name : String) -> void:
|
||||
var tmp_name = db_name.to_lower()
|
||||
var db_id = m_db_manager.add_database(db_name)
|
||||
if(db_id == gddb_constants.c_invalid_id):
|
||||
$dlg/error_dlg.set_text("Database with name \"" + db_name + "\" already exists")
|
||||
$dlg/error_dlg.popup_centered()
|
||||
return
|
||||
|
||||
var db = m_db_manager.get_db_by_id(db_id)
|
||||
# print("new DB added: " + str(db))
|
||||
|
||||
var db_editor = load(gddb_constants.c_addon_main_path + "db_editor.tscn").instance()
|
||||
$dlg/databases.add_child(db_editor)
|
||||
db_editor.set_name(db_name)
|
||||
db.set_dirty(true)
|
||||
db_editor.set_database(db)
|
||||
|
||||
$dlg/menu.enable_file_save(true)
|
||||
$dlg/menu.enable_file_save_as(true)
|
||||
|
||||
$dlg/new_db_dlg.hide()
|
||||
|
||||
# called when selecting a file from save / load dialog
|
||||
func on_file_selected(filepath : String) -> void:
|
||||
# print("GDDBInterface::on_file_selected(" + filepath + ")")
|
||||
|
||||
if($dlg/load_db_dlg.get_mode() == FileDialog.MODE_SAVE_FILE):
|
||||
var filepath_low = filepath.to_lower()
|
||||
|
||||
# check for the file extension
|
||||
if(!filepath_low.ends_with(".json")):
|
||||
$dlg/error_dlg.set_text("The extension of the file must be \".json\"")
|
||||
$dlg/error_dlg.popup_centered()
|
||||
return
|
||||
|
||||
var current_filename = $dlg/load_db_dlg.get_current_file().to_lower()
|
||||
var filename_dot = current_filename.length() - 5
|
||||
current_filename.erase(filename_dot, 5)
|
||||
|
||||
# check the filename
|
||||
if(!gddb_globals.check_db_name(current_filename)):
|
||||
$dlg/error_dlg.set_text("Invalid characters in the database filename.\n\nThe filename cannot contain any of these characters: " + gddb_constants.c_invalid_characters)
|
||||
$dlg/error_dlg.popup_centered()
|
||||
return
|
||||
|
||||
save_database_as(filepath)
|
||||
|
||||
elif($dlg/load_db_dlg.get_mode() == FileDialog.MODE_OPEN_FILE):
|
||||
load_database(filepath)
|
||||
|
||||
# saves a database to a given file path
|
||||
func save_database_as(filepath : String) -> void:
|
||||
# print("GDDBInterface::save_database_as(" + filepath + ")")
|
||||
var currnet_tab = $dlg/databases.get_current_tab_control()
|
||||
currnet_tab.set_database_filepath(filepath)
|
||||
currnet_tab.save_database()
|
||||
|
||||
func load_database(filepath : String) -> void:
|
||||
var db_id = m_db_manager.load_database(filepath)
|
||||
|
||||
if(db_id == gddb_types.e_db_invalid_file):
|
||||
$dlg/error_dlg.set_text("Invalid database")
|
||||
$dlg/error_dlg.popup_centered()
|
||||
return
|
||||
|
||||
if(db_id == gddb_types.e_db_invalid_ver):
|
||||
$dlg/error_dlg.set_text("Wrong database version. Currently is: " + gddb_constants.c_gddb_ver)
|
||||
$dlg/error_dlg.popup_centered()
|
||||
return
|
||||
|
||||
var db = m_db_manager.get_db_by_id(db_id)
|
||||
db.set_dirty(false)
|
||||
# print("new DB added: " + str(db))
|
||||
|
||||
var db_editor = load(gddb_constants.c_addon_main_path + "db_editor.tscn").instance()
|
||||
$dlg/databases.add_child(db_editor)
|
||||
db_editor.set_name(db.get_db_name())
|
||||
db_editor.set_database(db)
|
||||
|
||||
$dlg/menu.enable_file_save(true)
|
||||
$dlg/menu.enable_file_save_as(true)
|
||||
|
||||
db_editor.set_dirty(false)
|
||||
@@ -1,65 +0,0 @@
|
||||
[gd_scene load_steps=7 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/debug/dbg.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_18.tres" type="DynamicFont" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/error_dlg.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://addons/godot_db_manager/db_interface.gd" type="Script" id=4]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/new_db_dlg.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://addons/godot_db_manager/menu.tscn" type="PackedScene" id=7]
|
||||
|
||||
[node name="db_interface" type="Control"]
|
||||
script = ExtResource( 4 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ 30.0, 674.0 ],
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="dlg" type="WindowDialog" parent="."]
|
||||
visible = true
|
||||
margin_right = 1147.0
|
||||
margin_bottom = 768.0
|
||||
popup_exclusive = true
|
||||
window_title = "Godot Database Manager"
|
||||
resizable = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="menu" parent="dlg" instance=ExtResource( 7 )]
|
||||
|
||||
[node name="databases" type="TabContainer" parent="dlg"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = 30.0
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
tab_align = 0
|
||||
drag_to_rearrange_enabled = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="new_db_dlg" parent="dlg" instance=ExtResource( 5 )]
|
||||
visible = false
|
||||
margin_right = 3.832
|
||||
|
||||
[node name="error_dlg" parent="dlg" instance=ExtResource( 3 )]
|
||||
visible = false
|
||||
anchor_right = 0.187
|
||||
anchor_bottom = 0.136
|
||||
margin_right = 0.469986
|
||||
margin_bottom = -0.0800018
|
||||
|
||||
[node name="load_db_dlg" type="FileDialog" parent="dlg"]
|
||||
anchor_right = 0.349
|
||||
anchor_bottom = 0.418
|
||||
margin_right = -0.309998
|
||||
margin_bottom = 0.209991
|
||||
window_title = "Open a File"
|
||||
mode = 0
|
||||
filters = PoolStringArray( "*.json" )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="dbg" parent="dlg" instance=ExtResource( 1 )]
|
||||
visible = false
|
||||
@@ -1,33 +0,0 @@
|
||||
"""
|
||||
class GDDBManager
|
||||
"""
|
||||
|
||||
class_name GDDBManager
|
||||
|
||||
tool
|
||||
extends EditorPlugin
|
||||
|
||||
var DBInterface = preload("./db_interface.tscn")
|
||||
var db_interface : Node
|
||||
|
||||
func _enter_tree():
|
||||
add_autoload_singleton("gddb_constants", "res://addons/godot_db_manager/core/GDDBConstants.gd")
|
||||
add_autoload_singleton("gddb_types", "res://addons/godot_db_manager/core/GDDBTypes.gd")
|
||||
add_autoload_singleton("gddb_globals", "res://addons/godot_db_manager/core/GDDBGlobals.gd")
|
||||
|
||||
# Initialization of the plugin goes here
|
||||
db_interface = DBInterface.instance()
|
||||
|
||||
get_editor_interface().get_base_control().add_child(db_interface)
|
||||
add_tool_menu_item("Godot Database Manager", self, "open_config")
|
||||
|
||||
func _exit_tree():
|
||||
# Clean-up of the plugin goes here
|
||||
remove_tool_menu_item("Godot Database Manager")
|
||||
if(db_interface):
|
||||
db_interface.queue_free()
|
||||
|
||||
func open_config(UD):
|
||||
var window = db_interface.get_node("dlg") as WindowDialog
|
||||
if(window):
|
||||
window.popup_centered()
|
||||
@@ -1,79 +0,0 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/debug.png" type="Texture" id=1]
|
||||
|
||||
[node name="dbg" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="1" type="Control" parent="."]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
mouse_filter = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Sprite" type="Sprite" parent="1"]
|
||||
scale = Vector2( 4, 4 )
|
||||
texture = ExtResource( 1 )
|
||||
centered = false
|
||||
region_enabled = true
|
||||
region_rect = Rect2( 2, 50, 10, 10 )
|
||||
|
||||
[node name="2" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
margin_left = -40.0
|
||||
margin_bottom = 40.0
|
||||
mouse_filter = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Sprite" type="Sprite" parent="2"]
|
||||
scale = Vector2( 4, 4 )
|
||||
texture = ExtResource( 1 )
|
||||
centered = false
|
||||
region_enabled = true
|
||||
region_rect = Rect2( 2, 50, 10, 10 )
|
||||
|
||||
[node name="3" type="Control" parent="."]
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = -40.0
|
||||
margin_right = 40.0
|
||||
mouse_filter = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Sprite" type="Sprite" parent="3"]
|
||||
scale = Vector2( 4, 4 )
|
||||
texture = ExtResource( 1 )
|
||||
centered = false
|
||||
region_enabled = true
|
||||
region_rect = Rect2( 2, 50, 10, 10 )
|
||||
|
||||
[node name="4" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -40.0
|
||||
margin_top = -40.0
|
||||
mouse_filter = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Sprite" type="Sprite" parent="4"]
|
||||
scale = Vector2( 4, 4 )
|
||||
texture = ExtResource( 1 )
|
||||
centered = false
|
||||
region_enabled = true
|
||||
region_rect = Rect2( 2, 50, 10, 10 )
|
||||
@@ -1,61 +0,0 @@
|
||||
"""
|
||||
class GDDBDataPanel
|
||||
"""
|
||||
|
||||
class_name GDDBDataPanel
|
||||
|
||||
tool
|
||||
extends PopupPanel
|
||||
|
||||
signal select_data
|
||||
|
||||
var m_prop_id = gddb_constants.c_invalid_id
|
||||
var m_row_idx = gddb_constants.c_invalid_id
|
||||
|
||||
var m_table = null
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
connect("about_to_show", self, "on_about_to_show")
|
||||
$ItemList.connect("item_selected", self, "on_item_selected")
|
||||
|
||||
# sets property id
|
||||
func set_prop_id(prop_id : int) -> void :
|
||||
m_prop_id = prop_id
|
||||
|
||||
# returns property id
|
||||
func get_prop_id() -> int :
|
||||
return m_prop_id
|
||||
|
||||
# sets row index
|
||||
func set_row_idx(row_idx : int) -> void :
|
||||
m_row_idx = row_idx
|
||||
|
||||
# returns row index
|
||||
func get_row_idx() -> int :
|
||||
return m_row_idx
|
||||
|
||||
# sets the table from the database
|
||||
func set_table(table) -> void:
|
||||
m_table = table
|
||||
|
||||
# returns the table from the database
|
||||
func get_table() -> Object:
|
||||
return m_table
|
||||
|
||||
# called when the popup is about to show
|
||||
func on_about_to_show() -> void :
|
||||
$ItemList.clear()
|
||||
$ItemList.add_item("None")
|
||||
for idx in range(0, m_table.get_rows_count()):
|
||||
var option = gddb_globals.get_json_from_row(m_table, idx)
|
||||
$ItemList.add_item(option)
|
||||
|
||||
# called when an item is selected
|
||||
func on_item_selected(idx : int) -> void:
|
||||
# the first index is ""
|
||||
if(idx == 0):
|
||||
emit_signal("select_data", m_prop_id, m_row_idx, -1, "{}" )
|
||||
else:
|
||||
emit_signal("select_data", m_prop_id, m_row_idx, idx-1, $ItemList.get_item_text(idx) )
|
||||
hide()
|
||||
@@ -1,25 +0,0 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/data_dlg.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_12.tres" type="DynamicFont" id=2]
|
||||
|
||||
[node name="data_dlg" type="PopupPanel"]
|
||||
anchor_right = 0.285625
|
||||
anchor_bottom = 0.351111
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ItemList" type="ItemList" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 4.0
|
||||
margin_top = 4.0
|
||||
margin_right = -4.0
|
||||
margin_bottom = -4.0
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
items = [ "ababab", null, false, "cdcdcd", null, false, "efefef", null, false ]
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
"""
|
||||
class GDDBDeletePropDlg
|
||||
"""
|
||||
|
||||
class_name GDDBDeletePropDlg
|
||||
|
||||
tool
|
||||
extends WindowDialog
|
||||
|
||||
signal delete_prop
|
||||
|
||||
var m_prop_id = gddb_constants.c_invalid_id
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void :
|
||||
$v_layout/buttons/ok_btn.connect("pressed", self, "on_ok_btn_pressed")
|
||||
$v_layout/buttons/cancel_btn.connect("pressed", self, "on_cancel_btn_pressed")
|
||||
|
||||
# sets the property id
|
||||
func set_prop_id(prop_id : int) -> void :
|
||||
m_prop_id = prop_id
|
||||
|
||||
# returns the property id
|
||||
func get_prop_id() -> int :
|
||||
return m_prop_id
|
||||
|
||||
func set_prop_name(prop_name : String) -> void:
|
||||
var text = "Delete property with name \"" + prop_name + "\" ?"
|
||||
$v_layout/prop_info/prop_lbl.set_text(text)
|
||||
|
||||
# returns the table id
|
||||
func get_table_id() -> int :
|
||||
return m_prop_id
|
||||
|
||||
# called when the OK button is pressed
|
||||
func on_ok_btn_pressed() -> void :
|
||||
emit_signal("delete_prop")
|
||||
hide()
|
||||
|
||||
func on_cancel_btn_pressed() -> void:
|
||||
hide()
|
||||
@@ -1,66 +0,0 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/delete_prop_dlg.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_14.tres" type="DynamicFont" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_12.tres" type="DynamicFont" id=3]
|
||||
|
||||
[node name="delete_prop_dlg" type="WindowDialog"]
|
||||
visible = true
|
||||
anchor_right = 0.257
|
||||
anchor_bottom = 0.084
|
||||
margin_right = 0.799988
|
||||
margin_bottom = 0.399994
|
||||
focus_next = NodePath("v_layout/buttons/ok_btn")
|
||||
focus_mode = 1
|
||||
custom_fonts/title_font = ExtResource( 2 )
|
||||
popup_exclusive = true
|
||||
window_title = "Delete property"
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="v_layout" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_constants/separation = 10
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="prop_info" type="HBoxContainer" parent="v_layout"]
|
||||
margin_top = 13.0
|
||||
margin_right = 412.0
|
||||
margin_bottom = 30.0
|
||||
alignment = 1
|
||||
|
||||
[node name="prop_lbl" type="Label" parent="v_layout/prop_info"]
|
||||
margin_left = 152.0
|
||||
margin_right = 259.0
|
||||
margin_bottom = 17.0
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
text = "Property name: "
|
||||
|
||||
[node name="buttons" type="HBoxContainer" parent="v_layout"]
|
||||
margin_top = 40.0
|
||||
margin_right = 412.0
|
||||
margin_bottom = 61.0
|
||||
custom_constants/separation = 50
|
||||
alignment = 1
|
||||
|
||||
[node name="ok_btn" type="Button" parent="v_layout/buttons"]
|
||||
margin_left = 81.0
|
||||
margin_right = 181.0
|
||||
margin_bottom = 21.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "OK"
|
||||
|
||||
[node name="cancel_btn" type="Button" parent="v_layout/buttons"]
|
||||
margin_left = 231.0
|
||||
margin_right = 331.0
|
||||
margin_bottom = 21.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "Cancel"
|
||||
@@ -1,37 +0,0 @@
|
||||
"""
|
||||
class GDDBDeleteTableDlg
|
||||
"""
|
||||
|
||||
class_name GDDBDeleteTableDlg
|
||||
|
||||
tool
|
||||
extends WindowDialog
|
||||
|
||||
signal delete_table
|
||||
|
||||
var m_table_id = gddb_constants.c_invalid_id
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
$v_layout/buttons/ok_btn.connect("pressed", self, "on_ok_btn_pressed")
|
||||
$v_layout/buttons/cancel_btn.connect("pressed", self, "on_cancel_btn_pressed")
|
||||
|
||||
# sets the table id
|
||||
func set_table_id(table_id : int) -> void:
|
||||
m_table_id = table_id
|
||||
|
||||
func set_table_name(table_name : String) -> void:
|
||||
var text = "Delete table with name \"" + table_name + "\" ?"
|
||||
$v_layout/table_info/table_lbl.set_text(text)
|
||||
|
||||
# returns the table id
|
||||
func get_table_id() -> int:
|
||||
return m_table_id
|
||||
|
||||
# called when the OK button is pressed
|
||||
func on_ok_btn_pressed() -> void:
|
||||
emit_signal("delete_table")
|
||||
hide()
|
||||
|
||||
func on_cancel_btn_pressed() -> void:
|
||||
hide()
|
||||
@@ -1,66 +0,0 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/delete_table_dlg.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_14.tres" type="DynamicFont" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_12.tres" type="DynamicFont" id=3]
|
||||
|
||||
[node name="delete_table_dlg" type="WindowDialog"]
|
||||
visible = true
|
||||
anchor_right = 0.257
|
||||
anchor_bottom = 0.084
|
||||
margin_right = 0.799988
|
||||
margin_bottom = 0.399994
|
||||
focus_next = NodePath("v_layout/buttons/ok_btn")
|
||||
focus_mode = 1
|
||||
custom_fonts/title_font = ExtResource( 2 )
|
||||
popup_exclusive = true
|
||||
window_title = "Delete table"
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="v_layout" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_constants/separation = 10
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="table_info" type="HBoxContainer" parent="v_layout"]
|
||||
margin_top = 13.0
|
||||
margin_right = 412.0
|
||||
margin_bottom = 30.0
|
||||
alignment = 1
|
||||
|
||||
[node name="table_lbl" type="Label" parent="v_layout/table_info"]
|
||||
margin_left = 162.0
|
||||
margin_right = 249.0
|
||||
margin_bottom = 17.0
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
text = "Table name: "
|
||||
|
||||
[node name="buttons" type="HBoxContainer" parent="v_layout"]
|
||||
margin_top = 40.0
|
||||
margin_right = 412.0
|
||||
margin_bottom = 61.0
|
||||
custom_constants/separation = 50
|
||||
alignment = 1
|
||||
|
||||
[node name="ok_btn" type="Button" parent="v_layout/buttons"]
|
||||
margin_left = 81.0
|
||||
margin_right = 181.0
|
||||
margin_bottom = 21.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "OK"
|
||||
|
||||
[node name="cancel_btn" type="Button" parent="v_layout/buttons"]
|
||||
margin_left = 231.0
|
||||
margin_right = 331.0
|
||||
margin_bottom = 21.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "Cancel"
|
||||
@@ -1,59 +0,0 @@
|
||||
"""
|
||||
class GDDBEditStringDlg
|
||||
"""
|
||||
|
||||
class_name GDDBEditStringDlg
|
||||
|
||||
tool
|
||||
extends WindowDialog
|
||||
|
||||
signal string_edited
|
||||
|
||||
var m_prop_id = gddb_constants.c_invalid_id
|
||||
var m_row_idx = gddb_constants.c_invalid_id
|
||||
var m_data_text = ""
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
$v_layout/btns/ok_btn.connect("pressed", self, "on_ok_btn_pressed")
|
||||
$v_layout/btns/cancel_btn.connect("pressed", self, "on_cancel_btn_pressed")
|
||||
|
||||
$v_layout/text.connect("text_changed", self, "on_text_changed")
|
||||
|
||||
# sets property id
|
||||
func set_prop_id(prop_id : int) -> void:
|
||||
m_prop_id = prop_id
|
||||
|
||||
# returns property id
|
||||
func get_prop_id() -> int :
|
||||
return m_prop_id
|
||||
|
||||
# sets row index
|
||||
func set_row_idx(row_idx : int) -> void :
|
||||
m_row_idx = row_idx
|
||||
|
||||
# returns row index
|
||||
func get_row_idx() -> int :
|
||||
return m_row_idx
|
||||
|
||||
# sets data text
|
||||
func set_data_text(text : String) -> void :
|
||||
m_data_text = text
|
||||
$v_layout/text.set_text(text)
|
||||
|
||||
# returns data text
|
||||
func get_data_text() -> String :
|
||||
return m_data_text
|
||||
|
||||
# Called when the OK button is pressed
|
||||
func on_ok_btn_pressed() -> void :
|
||||
emit_signal("string_edited")
|
||||
hide()
|
||||
|
||||
# Called when the Cancel button is pressed
|
||||
func on_cancel_btn_pressed() -> void :
|
||||
hide()
|
||||
|
||||
# Called when text is changed
|
||||
func on_text_changed() -> void:
|
||||
m_data_text = $v_layout/text.get_text()
|
||||
@@ -1,60 +0,0 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/edit_string_dlg.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_14.tres" type="DynamicFont" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_12.tres" type="DynamicFont" id=3]
|
||||
|
||||
[node name="edit_string_dlg" type="WindowDialog"]
|
||||
anchor_right = 0.430625
|
||||
anchor_bottom = 0.423333
|
||||
focus_next = NodePath("v_layout/text")
|
||||
custom_fonts/title_font = ExtResource( 3 )
|
||||
window_title = "Edit string"
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": true
|
||||
}
|
||||
|
||||
[node name="v_layout" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="edit_text_btns" type="HBoxContainer" parent="v_layout"]
|
||||
margin_right = 689.0
|
||||
margin_bottom = 30.0
|
||||
rect_min_size = Vector2( 0, 30 )
|
||||
|
||||
[node name="text" type="TextEdit" parent="v_layout"]
|
||||
margin_top = 34.0
|
||||
margin_right = 689.0
|
||||
margin_bottom = 334.0
|
||||
rect_min_size = Vector2( 0, 300 )
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
caret_blink = true
|
||||
|
||||
[node name="btns" type="HBoxContainer" parent="v_layout"]
|
||||
margin_top = 338.0
|
||||
margin_right = 689.0
|
||||
margin_bottom = 368.0
|
||||
rect_min_size = Vector2( 0, 30 )
|
||||
custom_constants/separation = 200
|
||||
alignment = 1
|
||||
|
||||
[node name="ok_btn" type="Button" parent="v_layout/btns"]
|
||||
margin_left = 144.0
|
||||
margin_right = 244.0
|
||||
margin_bottom = 30.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "OK"
|
||||
|
||||
[node name="cancel_btn" type="Button" parent="v_layout/btns"]
|
||||
margin_left = 444.0
|
||||
margin_right = 544.0
|
||||
margin_bottom = 30.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "Cancel"
|
||||
@@ -1,11 +0,0 @@
|
||||
[gd_scene format=2]
|
||||
|
||||
[node name="error_dlg" type="AcceptDialog"]
|
||||
visible = true
|
||||
anchor_right = 0.139
|
||||
anchor_bottom = 0.099
|
||||
margin_right = 0.599976
|
||||
margin_bottom = -0.100006
|
||||
popup_exclusive = true
|
||||
window_title = "Error"
|
||||
dialog_autowrap = true
|
||||
@@ -1,76 +0,0 @@
|
||||
"""
|
||||
class GDDBLoadResourcePathDlg
|
||||
"""
|
||||
|
||||
class_name GDDBLoadResourcePathDlg
|
||||
|
||||
tool
|
||||
extends FileDialog
|
||||
|
||||
# TODO: put this list in a config file
|
||||
const file_filters = [
|
||||
# Godot resource file types
|
||||
"*.res, *.tres ; Godot resource file types",
|
||||
|
||||
# Godot scene files
|
||||
"*.scn, *.tscn, *escn ; Godot scene file types",
|
||||
|
||||
# Code file types
|
||||
"*.gd, *.cs, *.h, *.c, *.hpp, *.cpp ; Code file types",
|
||||
|
||||
# Shader file types
|
||||
"*.shader ; Shader file types",
|
||||
|
||||
# material file types
|
||||
"*.mat ; Material file types",
|
||||
|
||||
# mesh file types
|
||||
"*.dae, *.gltf, *.obj, *.fbx ; Mesh file types",
|
||||
|
||||
# animation file types
|
||||
"*.anim ; Animation file types",
|
||||
|
||||
# font file types
|
||||
"*.ttf, *.otf ; Font file types",
|
||||
|
||||
# image file types
|
||||
"*.png, *.jpg, *.jpeg, *.tiff, *.tga, *.bmp, *.webp, *.gif, *.hdr ; Images file types",
|
||||
|
||||
# soung file types
|
||||
"*.snd, *.wav, *.ogg, *.mp3 ; Sound file types",
|
||||
|
||||
# video file types
|
||||
"*.ogg, *.mpg, *.mpeg, *.avi, *.mov, *.mp4, *.webm ; Video file types",
|
||||
|
||||
# text file types
|
||||
"*.txt, *.csv, *.json, *.xml, *.cfg, *.ini ; Text file types",
|
||||
|
||||
# document file types
|
||||
"*.doc, *.docx, *.xls, *.xlsx, *.odt, *.ods, *.pdf ; Doc file types",
|
||||
|
||||
# binary data file types
|
||||
"*.dat, *.raw ; Binary data file types"
|
||||
]
|
||||
|
||||
var m_prop_id = gddb_constants.c_invalid_id
|
||||
var m_row_idx = gddb_constants.c_invalid_id
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
set_filters(PoolStringArray(file_filters))
|
||||
|
||||
# sets the property id
|
||||
func set_prop_id(prop_id : int) -> void :
|
||||
m_prop_id = prop_id
|
||||
|
||||
# returns the property id
|
||||
func get_prop_id() -> int :
|
||||
return m_prop_id
|
||||
|
||||
# sets the row index
|
||||
func set_row_idx(row_idx : int) -> void :
|
||||
m_row_idx = row_idx
|
||||
|
||||
# returns the row index
|
||||
func get_row_idx() -> int :
|
||||
return m_row_idx
|
||||
@@ -1,16 +0,0 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/load_res_path_dlg.gd" type="Script" id=1]
|
||||
|
||||
[node name="load_res_path_dlg" type="FileDialog"]
|
||||
anchor_right = 0.404
|
||||
anchor_bottom = 0.431
|
||||
margin_right = -0.400024
|
||||
margin_bottom = 0.0999756
|
||||
window_title = "Open a File"
|
||||
resizable = true
|
||||
mode = 0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
"""
|
||||
class GDDBNewDBDlg
|
||||
"""
|
||||
|
||||
class_name GDDBNewDBDlg
|
||||
|
||||
tool
|
||||
extends WindowDialog
|
||||
|
||||
signal create_new_db
|
||||
|
||||
var m_current_db_name = ""
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void :
|
||||
$v_layout/buttons/ok_btn.connect("pressed", self, "on_ok_btn_pressed")
|
||||
$v_layout/buttons/cancel_btn.connect("pressed", self, "on_cancel_btn_pressed")
|
||||
connect("about_to_show", self, "on_about_to_show")
|
||||
$v_layout/db_info/db_edt.connect("text_changed", self, "on_text_changed")
|
||||
$v_layout/db_info/db_edt.connect("text_entered", self, "on_text_confirmed")
|
||||
|
||||
# Called when the node is about to be shown.
|
||||
func on_about_to_show() -> void :
|
||||
m_current_db_name = ""
|
||||
$v_layout/db_info/db_edt.set_text(m_current_db_name)
|
||||
|
||||
# called everytime the text is changed
|
||||
func on_text_changed(new_text: String) -> void :
|
||||
var change_text = true
|
||||
if(!gddb_globals.check_db_name(new_text)):
|
||||
change_text = false
|
||||
else:
|
||||
if(new_text.length() > gddb_constants.c_max_db_name_len):
|
||||
change_text = false
|
||||
else:
|
||||
change_text = true
|
||||
|
||||
if(change_text):
|
||||
m_current_db_name = $v_layout/db_info/db_edt.get_text()
|
||||
else:
|
||||
$v_layout/db_info/db_edt.set_text(m_current_db_name)
|
||||
$v_layout/db_info/db_edt.set_cursor_position(m_current_db_name.length())
|
||||
|
||||
# called when the user presses the ENTER key
|
||||
func on_text_confirmed(text : String) -> void :
|
||||
# print("GDDBNewDBDlg::on_text_confirmed(" + text + ")")
|
||||
if(m_current_db_name.empty()):
|
||||
return
|
||||
handle_db_name()
|
||||
hide()
|
||||
|
||||
# called when the OK button is pressed
|
||||
func on_ok_btn_pressed() -> void :
|
||||
if(!m_current_db_name.empty()):
|
||||
handle_db_name()
|
||||
|
||||
# called when the Cancel button is pressed
|
||||
func on_cancel_btn_pressed() -> void :
|
||||
hide()
|
||||
|
||||
# handles the name of the database
|
||||
func handle_db_name() -> void :
|
||||
emit_signal("create_new_db", m_current_db_name)
|
||||
@@ -1,82 +0,0 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_14.tres" type="DynamicFont" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/new_db_dlg.gd" type="Script" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_12.tres" type="DynamicFont" id=3]
|
||||
|
||||
[node name="new_db_dlg" type="WindowDialog"]
|
||||
visible = true
|
||||
anchor_right = 0.257
|
||||
anchor_bottom = 0.1
|
||||
margin_right = 0.799988
|
||||
focus_next = NodePath("v_layout/db_info/db_edt")
|
||||
focus_mode = 2
|
||||
custom_fonts/title_font = ExtResource( 1 )
|
||||
popup_exclusive = true
|
||||
window_title = "New database (max 16 characters)"
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ 90.0781 ],
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="v_layout" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_constants/separation = 20
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="db_info" type="HBoxContainer" parent="v_layout"]
|
||||
margin_top = 11.0
|
||||
margin_right = 412.0
|
||||
margin_bottom = 38.0
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="db_lbl" type="Label" parent="v_layout/db_info"]
|
||||
margin_left = 18.0
|
||||
margin_top = 5.0
|
||||
margin_right = 89.0
|
||||
margin_bottom = 22.0
|
||||
custom_fonts/font = ExtResource( 1 )
|
||||
text = "DB name: "
|
||||
|
||||
[node name="db_edt" type="LineEdit" parent="v_layout/db_info"]
|
||||
margin_left = 93.0
|
||||
margin_right = 393.0
|
||||
margin_bottom = 27.0
|
||||
rect_min_size = Vector2( 300, 20 )
|
||||
custom_fonts/font = ExtResource( 1 )
|
||||
caret_blink = true
|
||||
caret_blink_speed = 0.5
|
||||
|
||||
[node name="buttons" type="HBoxContainer" parent="v_layout"]
|
||||
margin_top = 58.0
|
||||
margin_right = 412.0
|
||||
margin_bottom = 79.0
|
||||
custom_constants/separation = 80
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ok_btn" type="Button" parent="v_layout/buttons"]
|
||||
margin_left = 66.0
|
||||
margin_right = 166.0
|
||||
margin_bottom = 21.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "OK"
|
||||
|
||||
[node name="cancel_btn" type="Button" parent="v_layout/buttons"]
|
||||
margin_left = 246.0
|
||||
margin_right = 346.0
|
||||
margin_bottom = 21.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "Cancel"
|
||||
@@ -1,83 +0,0 @@
|
||||
"""
|
||||
class GDDBNewDBDlg
|
||||
"""
|
||||
|
||||
class_name GDDBNewTableDlg
|
||||
|
||||
tool
|
||||
extends WindowDialog
|
||||
|
||||
signal create_new_table
|
||||
signal cancel_dialog
|
||||
|
||||
var m_dlg_type : int = gddb_types.e_new_dlg_type_new
|
||||
var m_table_id = gddb_constants.c_invalid_id
|
||||
var m_current_table_name = ""
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
$v_layout/buttons/ok_btn.connect("pressed", self, "on_ok_btn_pressed")
|
||||
$v_layout/buttons/cancel_btn.connect("pressed", self, "on_cancel_btn_pressed")
|
||||
$v_layout/table_info/table_edt.connect("text_changed", self, "on_text_changed")
|
||||
$v_layout/table_info/table_edt.connect("text_entered", self, "on_text_confirmed")
|
||||
m_current_table_name = ""
|
||||
|
||||
# sets the type of the dialog
|
||||
func set_dld_type(dlg_type : int) -> void :
|
||||
m_dlg_type = dlg_type
|
||||
|
||||
# returns the dialog type
|
||||
func get_dlg_type() -> int :
|
||||
return m_dlg_type
|
||||
|
||||
# sets the table id
|
||||
func set_table_id(table_id : int) -> void:
|
||||
m_table_id = table_id
|
||||
|
||||
# returns the table id
|
||||
func get_table_id() -> int:
|
||||
return m_table_id
|
||||
|
||||
# sets the table name
|
||||
func set_init_name(table_name : String) -> void:
|
||||
# print("cNewTableDlg::set_init_name(" + name + ")")
|
||||
m_current_table_name = table_name
|
||||
$v_layout/table_info/table_edt.set_text(m_current_table_name)
|
||||
|
||||
func on_text_changed(new_text: String) -> void:
|
||||
var change_text = true
|
||||
if(!gddb_globals.check_db_name(new_text)):
|
||||
change_text = false
|
||||
else:
|
||||
if(new_text.length() > gddb_constants.c_max_db_name_len):
|
||||
change_text = false
|
||||
else:
|
||||
change_text = true
|
||||
|
||||
if(change_text):
|
||||
m_current_table_name = $v_layout/table_info/table_edt.get_text()
|
||||
else:
|
||||
$v_layout/table_info/table_edt.set_text(m_current_table_name)
|
||||
$v_layout/table_info/table_edt.set_cursor_position(m_current_table_name.length())
|
||||
|
||||
# called when the user presses the ENTER key
|
||||
func on_text_confirmed(text : String) -> void:
|
||||
if(m_current_table_name.empty()):
|
||||
return
|
||||
handle_table_name()
|
||||
hide()
|
||||
|
||||
# called when the OK button is pressed
|
||||
func on_ok_btn_pressed() -> void:
|
||||
if(!m_current_table_name.empty()):
|
||||
handle_table_name()
|
||||
hide()
|
||||
|
||||
# called when the Cancel button is pressed
|
||||
func on_cancel_btn_pressed() -> void :
|
||||
hide()
|
||||
emit_signal("cancel_dialog")
|
||||
|
||||
# handles the text in the EditLine
|
||||
func handle_table_name() -> void:
|
||||
emit_signal("create_new_table", m_current_table_name)
|
||||
@@ -1,73 +0,0 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_12.tres" type="DynamicFont" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/new_table_dlg.gd" type="Script" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_14.tres" type="DynamicFont" id=3]
|
||||
|
||||
[node name="new_table_dlg" type="WindowDialog"]
|
||||
visible = true
|
||||
anchor_right = 0.257
|
||||
anchor_bottom = 0.084
|
||||
margin_right = 0.799988
|
||||
margin_bottom = 0.399994
|
||||
focus_next = NodePath("v_layout/table_info/table_edt")
|
||||
focus_mode = 1
|
||||
custom_fonts/title_font = ExtResource( 3 )
|
||||
popup_exclusive = true
|
||||
window_title = "New table (max 16 characters)"
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="v_layout" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_constants/separation = 10
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="table_info" type="HBoxContainer" parent="v_layout"]
|
||||
margin_top = 8.0
|
||||
margin_right = 412.0
|
||||
margin_bottom = 35.0
|
||||
alignment = 1
|
||||
|
||||
[node name="table_lbl" type="Label" parent="v_layout/table_info"]
|
||||
margin_left = 10.0
|
||||
margin_top = 5.0
|
||||
margin_right = 97.0
|
||||
margin_bottom = 22.0
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "Table name: "
|
||||
|
||||
[node name="table_edt" type="LineEdit" parent="v_layout/table_info"]
|
||||
margin_left = 101.0
|
||||
margin_right = 401.0
|
||||
margin_bottom = 27.0
|
||||
rect_min_size = Vector2( 300, 20 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
caret_blink = true
|
||||
caret_blink_speed = 0.5
|
||||
|
||||
[node name="buttons" type="HBoxContainer" parent="v_layout"]
|
||||
margin_top = 45.0
|
||||
margin_right = 412.0
|
||||
margin_bottom = 66.0
|
||||
custom_constants/separation = 80
|
||||
alignment = 1
|
||||
|
||||
[node name="ok_btn" type="Button" parent="v_layout/buttons"]
|
||||
margin_left = 66.0
|
||||
margin_right = 166.0
|
||||
margin_bottom = 21.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 1 )
|
||||
text = "OK"
|
||||
|
||||
[node name="cancel_btn" type="Button" parent="v_layout/buttons"]
|
||||
margin_left = 246.0
|
||||
margin_right = 346.0
|
||||
margin_bottom = 21.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 1 )
|
||||
text = "Cancel"
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,34 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-8476557a42180e1e377aacb0cfda943e.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot_db_manager/icon/icon.png"
|
||||
dest_files=[ "res://.import/icon.png-8476557a42180e1e377aacb0cfda943e.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
Binary file not shown.
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Radu Bolovan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,101 +0,0 @@
|
||||
"""
|
||||
class GDDBMenu
|
||||
"""
|
||||
|
||||
class_name GDDBMenu
|
||||
|
||||
tool
|
||||
extends Control
|
||||
|
||||
signal new_database
|
||||
signal load_database
|
||||
signal save_database
|
||||
signal save_database_as
|
||||
|
||||
enum {
|
||||
e_file_new_id = 0,
|
||||
e_file_load_id = 1
|
||||
e_file_save_id = 2,
|
||||
e_file_save_as_id = 3,
|
||||
|
||||
e_option_autosave_on_close_id = 4
|
||||
}
|
||||
|
||||
var m_enable_new_db = true
|
||||
var m_enable_load_db = true
|
||||
var m_enable_save_db = false
|
||||
var m_enable_save_as_db = false
|
||||
|
||||
var m_check_autosave_on_load = false
|
||||
|
||||
func _ready() -> void:
|
||||
$layout/File.connect("about_to_show", self, "on_about_to_show_file_menu")
|
||||
$layout/File.get_popup().clear()
|
||||
$layout/File.get_popup().add_item("New DB", e_file_new_id)
|
||||
$layout/File.get_popup().add_item("Load DB", e_file_load_id)
|
||||
$layout/File.get_popup().add_item("Save DB", e_file_save_id)
|
||||
$layout/File.get_popup().add_item("Save DB As ...", e_file_save_as_id)
|
||||
$layout/File.get_popup().connect("id_pressed", self, "on_file_id_pressed")
|
||||
|
||||
$layout/Options.connect("about_to_show", self, "on_about_to_show_options_menu")
|
||||
$layout/Options.get_popup().clear()
|
||||
$layout/Options.get_popup().add_check_item("Autosave on close", e_option_autosave_on_close_id)
|
||||
$layout/Options.get_popup().connect("id_pressed", self, "on_options_id_pressed")
|
||||
|
||||
# called before showing the file menu
|
||||
func on_about_to_show_file_menu() -> void:
|
||||
for idx in range(0, $layout/File.get_popup().get_item_count()):
|
||||
var item_id = $layout/File.get_popup().get_item_id(idx)
|
||||
if(item_id == e_file_new_id):
|
||||
$layout/File.get_popup().set_item_disabled(idx, !m_enable_new_db)
|
||||
elif(item_id == e_file_load_id):
|
||||
$layout/File.get_popup().set_item_disabled(idx, !m_enable_load_db)
|
||||
elif(item_id == e_file_save_id):
|
||||
$layout/File.get_popup().set_item_disabled(idx, !m_enable_save_db)
|
||||
elif(item_id == e_file_save_as_id):
|
||||
$layout/File.get_popup().set_item_disabled(idx, !m_enable_save_as_db)
|
||||
raise()
|
||||
|
||||
# enables / disables the possibility to create a new databbase
|
||||
func enable_file_new(enable) -> void:
|
||||
m_enable_new_db = enable
|
||||
|
||||
# enables / disables the possibility to load a databbase
|
||||
func enable_file_load(enable) -> void:
|
||||
m_enable_load_db = enable
|
||||
|
||||
# enables / disables the possibility to save a databbase
|
||||
func enable_file_save(enable) -> void:
|
||||
m_enable_save_db = enable
|
||||
|
||||
# enables / disables the possibility to save a databbase as another
|
||||
func enable_file_save_as(enable) -> void:
|
||||
m_enable_save_as_db = enable
|
||||
|
||||
# called when the user clicks on a file menu item
|
||||
func on_file_id_pressed(id : int) -> void:
|
||||
if(id == e_file_new_id):
|
||||
emit_signal("new_database")
|
||||
elif(id == e_file_load_id):
|
||||
emit_signal("load_database")
|
||||
elif(id == e_file_save_id):
|
||||
emit_signal("save_database")
|
||||
elif(id == e_file_save_as_id):
|
||||
emit_signal("save_database_as")
|
||||
|
||||
# called before showing the option menu
|
||||
func on_about_to_show_options_menu() -> void:
|
||||
for idx in range(0, $layout/Options.get_popup().get_item_count()):
|
||||
var item_id = $layout/Options.get_popup().get_item_id(idx)
|
||||
if(item_id == e_option_autosave_on_close_id):
|
||||
$layout/Options.get_popup().set_item_checked(idx, m_check_autosave_on_load)
|
||||
raise()
|
||||
|
||||
# enables / disables the possibility to autosave all databases on close
|
||||
func enable_autosave_on_close(enable) -> void:
|
||||
m_check_autosave_on_load = enable
|
||||
|
||||
# called when the user clicks on a options menu item
|
||||
func on_options_id_pressed(id : int) -> void:
|
||||
if(id == e_option_autosave_on_close_id):
|
||||
enable_autosave_on_close(!m_check_autosave_on_load)
|
||||
@@ -1,36 +0,0 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/menu.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_18.tres" type="DynamicFont" id=2]
|
||||
|
||||
[node name="menu" type="Control"]
|
||||
anchor_right = 1.0
|
||||
rect_min_size = Vector2( 0, 30 )
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ 30.0 ],
|
||||
"_edit_use_anchors_": false,
|
||||
"_edit_vertical_guides_": [ 1024.0 ]
|
||||
}
|
||||
|
||||
[node name="layout" type="HBoxContainer" parent="."]
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 30.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="File" type="MenuButton" parent="layout"]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 30.0
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
text = "File"
|
||||
items = [ "New DB", null, 0, false, false, 0, 0, null, "", false, "Load DB", null, 0, false, false, 1, 0, null, "", false, "Save DB", null, 0, false, false, 2, 0, null, "", false, "Save DB As ...", null, 0, false, false, 3, 0, null, "", false ]
|
||||
|
||||
[node name="Options" type="MenuButton" parent="layout"]
|
||||
margin_left = 44.0
|
||||
margin_right = 117.0
|
||||
margin_bottom = 30.0
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
text = "Options"
|
||||
items = [ "Autosave on close", null, 1, false, false, 4, 0, null, "", false ]
|
||||
@@ -1,7 +0,0 @@
|
||||
[plugin]
|
||||
|
||||
name="Godot Database Manager"
|
||||
description="A database manager plugin for Google Engine."
|
||||
author="Radu Bolovan"
|
||||
version="2.1.a"
|
||||
script="db_manager.gd"
|
||||
@@ -1,221 +0,0 @@
|
||||
"""
|
||||
class GDDBTableCell
|
||||
"""
|
||||
|
||||
class_name GDDBTableCell
|
||||
|
||||
tool
|
||||
extends Control
|
||||
|
||||
signal edit_data
|
||||
signal choose_resource
|
||||
signal choose_data
|
||||
signal edit_string
|
||||
|
||||
const c_cell_min_width = 150
|
||||
|
||||
var m_prop_id : int = -1
|
||||
var m_prop_type : int = gddb_constants.c_invalid_id
|
||||
var m_row_idx : int = -1
|
||||
var m_text : String = ""
|
||||
|
||||
func _ready() -> void :
|
||||
$LineEdit.connect("text_changed", self, "on_text_changed")
|
||||
$LineEdit/edit_btn.connect("pressed", self, "on_edit_string")
|
||||
|
||||
$Button.connect("pressed", self, "on_button_pressed")
|
||||
$Button.set_clip_text(true)
|
||||
|
||||
$CheckBox.connect("toggled", self, "on_toggle_button")
|
||||
|
||||
func _exit_tree() -> void :
|
||||
$LineEdit.disconnect("text_changed", self, "on_text_changed")
|
||||
|
||||
# sets the property id
|
||||
func set_prop_id(id : int) -> void :
|
||||
m_prop_id = id
|
||||
|
||||
# returns the property id
|
||||
func get_prop_id() -> int :
|
||||
return m_prop_id
|
||||
|
||||
# sets property type
|
||||
func set_prop_type(data_type : int) -> void :
|
||||
# print("GDDBTableCell::set_prop_type(" + str(data_type) + ")")
|
||||
|
||||
var data_type_changed = false
|
||||
|
||||
if(m_prop_type != data_type):
|
||||
m_prop_type = data_type
|
||||
data_type_changed = true
|
||||
|
||||
if(!data_type_changed):
|
||||
return
|
||||
|
||||
if(m_prop_type == gddb_types.e_prop_type_bool):
|
||||
$LineEdit.hide()
|
||||
$Button.hide()
|
||||
$CheckBox.show()
|
||||
set_text("")
|
||||
elif(m_prop_type == gddb_types.e_prop_type_int):
|
||||
$LineEdit.show()
|
||||
$LineEdit/edit_btn.hide()
|
||||
$Button.hide()
|
||||
$CheckBox.hide()
|
||||
set_text("0")
|
||||
elif(m_prop_type == gddb_types.e_prop_type_float):
|
||||
$LineEdit.show()
|
||||
$LineEdit/edit_btn.hide()
|
||||
$Button.hide()
|
||||
$CheckBox.hide()
|
||||
set_text("0.0")
|
||||
elif(m_prop_type == gddb_types.e_prop_type_string):
|
||||
$LineEdit.show()
|
||||
$LineEdit/edit_btn.show()
|
||||
$Button.hide()
|
||||
$CheckBox.hide()
|
||||
set_text("")
|
||||
elif(m_prop_type == gddb_types.e_prop_type_resource):
|
||||
$LineEdit.hide()
|
||||
$Button.show()
|
||||
$CheckBox.hide()
|
||||
set_text("res://")
|
||||
elif(m_prop_type >= gddb_types.e_prop_types_count):
|
||||
$LineEdit.hide()
|
||||
$Button.show()
|
||||
$CheckBox.hide()
|
||||
set_text("{}")
|
||||
|
||||
func get_prop_type() -> int :
|
||||
return m_prop_type
|
||||
|
||||
# sets the row index
|
||||
func set_row_idx(idx : int) -> void :
|
||||
m_row_idx = idx
|
||||
|
||||
# returns the property index
|
||||
func get_row_idx() -> int :
|
||||
return m_row_idx
|
||||
|
||||
# sets the text
|
||||
func set_text(text : String) -> void :
|
||||
# print("GDDBTableCell::set_text(" + text + ")")
|
||||
m_text = text
|
||||
$LineEdit.set_text(m_text)
|
||||
$Button.set_text(m_text)
|
||||
if(m_prop_type == gddb_types.e_prop_type_bool):
|
||||
$CheckBox.set_pressed((text == "1"))
|
||||
|
||||
# sets autoincrement
|
||||
func enable_autoincrement(enable : bool) -> void :
|
||||
$LineEdit.set_editable(!enable)
|
||||
|
||||
# refreshes the width by the property name
|
||||
func refresh_width(prop_name : String) -> void :
|
||||
var size = get_custom_minimum_size()
|
||||
size.x = max(c_cell_min_width, get_font("normal_font").get_string_size(prop_name).x + 10)
|
||||
set_custom_minimum_size(size)
|
||||
|
||||
# called when the checkbox is toggled/untoggled
|
||||
func on_toggle_button(enable : bool) -> void :
|
||||
var data = "0"
|
||||
if(enable):
|
||||
data = "1"
|
||||
emit_signal("edit_data", m_prop_id, m_row_idx, data)
|
||||
|
||||
# called when the button is pressed
|
||||
func on_button_pressed() -> void :
|
||||
if(m_prop_type == gddb_types.e_prop_type_resource):
|
||||
# print("GDDBTableCell::on_button_pressed()")
|
||||
emit_signal("choose_resource", m_prop_id, m_row_idx)
|
||||
elif(m_prop_type >= gddb_types.e_prop_types_count):
|
||||
emit_signal("choose_data", m_prop_id, m_row_idx, m_prop_type)
|
||||
|
||||
# called when the edit string button is pressed
|
||||
func on_edit_string() -> void :
|
||||
emit_signal("edit_string", m_prop_id, m_row_idx, m_text)
|
||||
|
||||
# called when edit the data
|
||||
func on_text_changed(new_text : String) -> void :
|
||||
if(new_text.empty()):
|
||||
m_text = ""
|
||||
$LineEdit.set_text(m_text)
|
||||
$LineEdit.set_cursor_position(0)
|
||||
return
|
||||
|
||||
if(m_prop_type == gddb_types.e_prop_type_int):
|
||||
if(!check_integer(new_text)):
|
||||
return
|
||||
|
||||
if(m_prop_type == gddb_types.e_prop_type_float):
|
||||
if(!check_float(new_text)):
|
||||
return
|
||||
|
||||
emit_signal("edit_data", m_prop_id, m_row_idx, new_text)
|
||||
|
||||
# checks if the text is integer
|
||||
func check_integer(text : String) -> bool :
|
||||
var is_negative = false
|
||||
|
||||
# check if the string is probably a number, but starts with "-"
|
||||
if(text.begins_with("-")):
|
||||
text.erase(0, 1)
|
||||
is_negative = true
|
||||
|
||||
# check if the current string is only "-"
|
||||
if(text.empty()):
|
||||
m_text = "-"
|
||||
$LineEdit.set_text(m_text)
|
||||
$LineEdit.set_cursor_position(m_text.length())
|
||||
return true
|
||||
|
||||
if(text.is_valid_integer()):
|
||||
if(text.begins_with("0")):
|
||||
# a negative integer cannot start with "0"
|
||||
if(is_negative):
|
||||
m_text = "-"
|
||||
$LineEdit.set_text(m_text)
|
||||
$LineEdit.set_cursor_position(1)
|
||||
return true
|
||||
|
||||
# a positive number starting with "0" can be only "0"
|
||||
m_text = "0"
|
||||
$LineEdit.set_text(m_text)
|
||||
$LineEdit.set_cursor_position(1)
|
||||
return true
|
||||
|
||||
# don't add more "-" in front of the number
|
||||
if(text.begins_with("-")):
|
||||
text.erase(0, 1)
|
||||
|
||||
# add back the "-"
|
||||
if(is_negative):
|
||||
m_text = "-" + text
|
||||
else:
|
||||
m_text = text
|
||||
|
||||
$LineEdit.set_text(m_text)
|
||||
$LineEdit.set_cursor_position(m_text.length())
|
||||
return true
|
||||
|
||||
$LineEdit.set_text(m_text)
|
||||
$LineEdit.set_cursor_position(m_text.length())
|
||||
return false
|
||||
|
||||
func check_float(text : String) -> bool :
|
||||
if(text.is_valid_float()):
|
||||
if(text.begins_with("00") || text.begins_with("01") || text.begins_with("02")
|
||||
|| text.begins_with("03") || text.begins_with("04") || text.begins_with("05")
|
||||
|| text.begins_with("06") || text.begins_with("07") || text.begins_with("08")
|
||||
|| text.begins_with("09")):
|
||||
m_text = "0"
|
||||
$LineEdit.set_text(m_text)
|
||||
$LineEdit.set_cursor_position(1)
|
||||
return true
|
||||
|
||||
m_text = text
|
||||
return true
|
||||
|
||||
$LineEdit.set_text(m_text)
|
||||
$LineEdit.set_cursor_position(m_text.length())
|
||||
return false
|
||||
@@ -1,72 +0,0 @@
|
||||
[gd_scene load_steps=7 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/gui.png" type="Texture" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/table_cell.gd" type="Script" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_18.tres" type="DynamicFont" id=3]
|
||||
|
||||
[sub_resource type="AtlasTexture" id=1]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 28, 1.86734, 24, 24.1327 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=2]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 28, 54, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=3]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 28, 28, 24, 24 )
|
||||
|
||||
[node name="table_cell" type="Control"]
|
||||
anchor_right = 1.0
|
||||
margin_bottom = 15.36
|
||||
rect_min_size = Vector2( 150, 32 )
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ 32.0 ],
|
||||
"_edit_use_anchors_": true
|
||||
}
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.914286
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "TESTING WWW"
|
||||
caret_blink = true
|
||||
caret_blink_speed = 0.5
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": true
|
||||
}
|
||||
|
||||
[node name="edit_btn" type="TextureButton" parent="LineEdit"]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -29.0
|
||||
margin_top = 4.0
|
||||
margin_right = -5.0
|
||||
margin_bottom = -4.0
|
||||
texture_normal = SubResource( 1 )
|
||||
texture_pressed = SubResource( 2 )
|
||||
texture_hover = SubResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": true
|
||||
}
|
||||
|
||||
[node name="Button" type="Button" parent="."]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
clip_text = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="CheckBox" type="CheckBox" parent="."]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
@@ -1,433 +0,0 @@
|
||||
"""
|
||||
class GDDBTableEditor
|
||||
"""
|
||||
|
||||
class_name GDDBTableEditor
|
||||
|
||||
tool
|
||||
extends Control
|
||||
|
||||
signal set_dirty
|
||||
|
||||
var m_parent_table = null
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
$tabs/structure/header/new_property_btn.connect("pressed", self, "on_new_property_btn_pressed")
|
||||
$tabs/data/add_data_btn.connect("pressed", self, "on_add_row_data_btn_pressed")
|
||||
$tabs/data/add_data_btn.set_disabled(true)
|
||||
|
||||
$load_res_path_dlg.connect("file_selected", self, "on_select_res_path")
|
||||
|
||||
$data_dlg.connect("select_data", self, "on_select_data")
|
||||
|
||||
$edit_string_dlg.connect("string_edited", self, "on_text_edited")
|
||||
|
||||
$delete_prop_dlg.connect("delete_prop", self, "on_confirm_delete_property")
|
||||
|
||||
# called when resizing a property
|
||||
func on_resize_property(prop_id : int, diff_x : float) -> void :
|
||||
var current_prop = null
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_header.get_child_count()):
|
||||
var prop = $tabs/data/scroll/data_holder/data_header.get_child(idx)
|
||||
if(prop.get_prop_id() == prop_id):
|
||||
current_prop = prop
|
||||
break
|
||||
|
||||
var prop_size : Vector2 = current_prop.get_child(0).get_size()
|
||||
|
||||
# print("diff_x: " + str(diff_x))
|
||||
prop_size.x += diff_x
|
||||
|
||||
if(prop_size.x < gddb_constants.c_min_cell_width):
|
||||
return
|
||||
if(prop_size.x > gddb_constants.c_max_cell_width):
|
||||
return
|
||||
|
||||
# print("prop_size.x = " + str(prop_size.x))
|
||||
|
||||
var prop_idx = -1
|
||||
|
||||
var data_size = $tabs/data/scroll.get_size()
|
||||
data_size.x += diff_x
|
||||
$tabs/data/scroll/data_holder/data_header.set_size(data_size)
|
||||
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_header.get_child_count()):
|
||||
var prop = $tabs/data/scroll/data_holder/data_header.get_child(idx)
|
||||
if(prop.get_prop_id() == prop_id):
|
||||
var current_prop_size = prop.get_custom_minimum_size()
|
||||
current_prop_size.x += diff_x
|
||||
prop.set_custom_minimum_size(current_prop_size)
|
||||
prop_idx = idx
|
||||
|
||||
if(prop_idx != -1 && idx > prop_idx):
|
||||
var pos = prop.get_position()
|
||||
pos.x += diff_x
|
||||
prop.set_position(pos)
|
||||
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_container.get_child_count()):
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(idx)
|
||||
for jdx in range(0, row.get_child_count()):
|
||||
var cell = row.get_child(jdx)
|
||||
if(cell.get_prop_id() == prop_id):
|
||||
cell.set_custom_minimum_size(prop_size)
|
||||
if(jdx > prop_idx):
|
||||
var pos = cell.get_position()
|
||||
pos.x += diff_x
|
||||
cell.set_position(pos)
|
||||
|
||||
# called when the new_property button is pressed
|
||||
func on_new_property_btn_pressed() -> void:
|
||||
# print("GDDBTableEditor::on_new_property_btn_pressed()")
|
||||
if(null == m_parent_table):
|
||||
print("ERROR: GDDBTableEditor::on_new_property_btn_pressed() - m_parent_table is null")
|
||||
return
|
||||
var prop_idx = m_parent_table.get_props_count()
|
||||
var prop_type = gddb_types.e_prop_type_bool
|
||||
var prop_name = "Property_" + str(prop_idx+1)
|
||||
var prop_id = m_parent_table.add_prop(prop_type, prop_name)
|
||||
add_prop_to_structure(prop_id, prop_type, prop_name)
|
||||
add_prop_to_data(prop_id, prop_type, prop_name, false)
|
||||
|
||||
# enable add data btn
|
||||
$tabs/data/add_data_btn.set_disabled(false)
|
||||
|
||||
emit_signal("set_dirty")
|
||||
|
||||
# adds a property to structure tab
|
||||
func add_prop_to_structure(prop_id : int, prop_type : int, prop_name : String) -> void:
|
||||
# print("GDDBTableEditor::add_prop_to_structure(" + str(prop_id) + ", " + str(prop_type) + ", " + prop_name + ")")
|
||||
var prop = load(gddb_constants.c_addon_main_path + "table_property.tscn").instance()
|
||||
$tabs/structure/scroll/properties.add_child(prop)
|
||||
prop.set_parent_table(m_parent_table)
|
||||
prop.setup(prop_id, prop_type, prop_name)
|
||||
prop.connect("edit_property", self, "on_edit_property")
|
||||
prop.connect("delete_property", self, "on_delete_property")
|
||||
prop.connect("enable_autoincrement", self, "on_enable_prop_autoincrement")
|
||||
|
||||
# adds a property to data tab
|
||||
func add_prop_to_data(prop_id : int, prop_type : int, prop_name : String, has_autoincrement : bool) -> void:
|
||||
var prop = load(gddb_constants.c_addon_main_path + "data_label.tscn").instance()
|
||||
$tabs/data/scroll/data_holder/data_header.add_child(prop)
|
||||
prop.set_prop_id(prop_id)
|
||||
prop.set_text(prop_name)
|
||||
prop.connect("resize_property", self, "on_resize_property")
|
||||
|
||||
# add property to the existing rows
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_container.get_child_count()):
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(idx)
|
||||
var cell = load(gddb_constants.c_addon_main_path + "table_cell.tscn").instance()
|
||||
row.add_child(cell)
|
||||
cell.set_prop_id(prop_id)
|
||||
cell.set_row_idx(idx)
|
||||
cell.set_prop_type(prop_type)
|
||||
cell.set_text("")
|
||||
cell.enable_autoincrement(has_autoincrement)
|
||||
cell.connect("edit_data", self, "on_edit_data")
|
||||
cell.connect("choose_resource", self, "on_choose_resource")
|
||||
cell.connect("choose_data", self, "on_choose_data")
|
||||
cell.connect("edit_string", self, "on_edit_string")
|
||||
|
||||
# called when the add data button is pressed
|
||||
func on_add_row_data_btn_pressed() -> void:
|
||||
# print("GDDBTableEditor::on_add_row_data_btn_pressed")
|
||||
# add blank row in the table
|
||||
var row_idx = m_parent_table.get_rows_count()
|
||||
m_parent_table.add_blank_row()
|
||||
|
||||
# add row in the interface
|
||||
var row = HBoxContainer.new()
|
||||
$tabs/data/scroll/data_holder/data_container.add_child(row)
|
||||
for idx in range(0, $tabs/structure/scroll/properties.get_child_count()):
|
||||
var cell = load(gddb_constants.c_addon_main_path + "table_cell.tscn").instance()
|
||||
var prop = $tabs/structure/scroll/properties.get_child(idx)
|
||||
var db_prop = m_parent_table.get_prop_by_id(idx)
|
||||
row.add_child(cell)
|
||||
cell.set_prop_id(idx)
|
||||
cell.set_row_idx(row_idx)
|
||||
cell.set_prop_type(prop.get_prop_type())
|
||||
var autoincrement = db_prop.has_autoincrement()
|
||||
cell.enable_autoincrement(db_prop.has_autoincrement())
|
||||
if(autoincrement):
|
||||
cell.set_text(str(row_idx+1))
|
||||
cell.connect("edit_data", self, "on_edit_data")
|
||||
cell.connect("choose_resource", self, "on_choose_resource")
|
||||
cell.connect("choose_data", self, "on_choose_data")
|
||||
cell.connect("edit_string", self, "on_edit_string")
|
||||
|
||||
emit_signal("set_dirty")
|
||||
|
||||
# sets the table from database
|
||||
func set_table(table : Object) -> void:
|
||||
# print("GDDBTableEditor::set_table(" + table.get_table_name() + ")")
|
||||
clear_current_layout()
|
||||
|
||||
m_parent_table = table
|
||||
fill_properties()
|
||||
fill_data()
|
||||
|
||||
# fills the interface with current table's properties
|
||||
func fill_properties() -> void:
|
||||
# print("GDDBTableEditor::fill_properties()")
|
||||
var props_count = m_parent_table.get_props_count()
|
||||
for idx in range(0, props_count):
|
||||
var db_prop = m_parent_table.get_prop_at(idx)
|
||||
add_prop_to_structure(db_prop.get_prop_id(), db_prop.get_prop_type(), db_prop.get_prop_name())
|
||||
var prop = load(gddb_constants.c_addon_main_path + "data_label.tscn").instance()
|
||||
$tabs/data/scroll/data_holder/data_header.add_child(prop)
|
||||
prop.set_prop_id(db_prop.get_prop_id())
|
||||
prop.set_prop_type(db_prop.get_prop_type())
|
||||
prop.set_text(db_prop.get_prop_name())
|
||||
prop.connect("resize_property", self, "on_resize_property")
|
||||
if(props_count > 0):
|
||||
$tabs/data/add_data_btn.set_disabled(false)
|
||||
|
||||
# fills the interface with current table's data
|
||||
func fill_data() -> void:
|
||||
#print("GDDBTableEditor::fill_data()")
|
||||
var rows_count = m_parent_table.get_rows_count()
|
||||
#print("Table name: " + m_parent_table.get_table_name())
|
||||
#print("rows_count: " + str(rows_count))
|
||||
for idx in range(0, rows_count):
|
||||
var row = HBoxContainer.new()
|
||||
$tabs/data/scroll/data_holder/data_container.add_child(row)
|
||||
var data_row = m_parent_table.get_data_at_row_idx(idx)
|
||||
for jdx in range(0, data_row.size()):
|
||||
var db_prop = m_parent_table.get_prop_at(jdx)
|
||||
#print("Prop id: " + str(db_prop.get_prop_id()))
|
||||
#print("Prop type: " + str(db_prop.get_prop_type()))
|
||||
#print("Prop name: " + str(db_prop.get_prop_name()))
|
||||
|
||||
var cell = load(gddb_constants.c_addon_main_path + "table_cell.tscn").instance()
|
||||
var cell_data = data_row[jdx].get_data()
|
||||
|
||||
var prop_type = db_prop.get_prop_type()
|
||||
if(prop_type >= gddb_types.e_prop_types_count):
|
||||
var db = m_parent_table.get_parent_database()
|
||||
var table = db.get_table_by_id(prop_type - gddb_types.e_prop_types_count)
|
||||
var data_row_idx = cell_data.to_int()
|
||||
cell_data = gddb_globals.get_json_from_row(table, data_row_idx)
|
||||
|
||||
row.add_child(cell)
|
||||
|
||||
cell.set_prop_id(data_row[jdx].get_prop_id())
|
||||
cell.set_row_idx(idx)
|
||||
cell.set_prop_type(prop_type)
|
||||
cell.set_text(cell_data)
|
||||
cell.enable_autoincrement(db_prop.has_autoincrement())
|
||||
cell.connect("edit_data", self, "on_edit_data")
|
||||
cell.connect("choose_resource", self, "on_choose_resource")
|
||||
cell.connect("choose_data", self, "on_choose_data")
|
||||
cell.connect("edit_string", self, "on_edit_string")
|
||||
|
||||
# links properties
|
||||
func link_props() -> void :
|
||||
# print("GDDBTableEditor::link_props() for table with name: " + m_parent_table.get_table_name())
|
||||
for idx in range(0, $tabs/structure/scroll/properties.get_child_count()):
|
||||
var prop = $tabs/structure/scroll/properties.get_child(idx)
|
||||
prop.link()
|
||||
|
||||
# refreshes autoincrement props
|
||||
func refresh_autoincrement_props(prop_id, enable) -> void:
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_container.get_child_count()):
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(idx)
|
||||
for jdx in range(0, row.get_child_count()):
|
||||
var cell = row.get_child(jdx)
|
||||
if(cell.get_prop_id() == prop_id):
|
||||
cell.enable_autoincrement(enable)
|
||||
|
||||
# cleares current layout
|
||||
func clear_current_layout() -> void:
|
||||
# clear structure tab
|
||||
for idx in range(0, $tabs/structure/scroll/properties.get_child_count()):
|
||||
$tabs/structure/scroll/properties.get_child(idx).queue_free()
|
||||
|
||||
# clear data from data tab
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_container.get_child_count()):
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(idx)
|
||||
for jdx in range(0, row.get_child_count()):
|
||||
row.get_child(jdx).queue_free()
|
||||
row.queue_free()
|
||||
|
||||
# clear properties from data tab
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_header.get_child_count()):
|
||||
$tabs/data/scroll/data_holder/data_header.get_child(idx).queue_free()
|
||||
|
||||
$tabs/data/add_data_btn.set_disabled(true)
|
||||
|
||||
# called when a property is edited
|
||||
func on_edit_property(prop_id : int, prop_type : int, prop_name : String) -> void:
|
||||
"""
|
||||
print("GDDBTableEditor::on_edit_property(" + str(prop_id) + ", " + str(prop_type) + ", " + prop_name + ")")
|
||||
if(prop_type >= gddb_types.e_prop_types_count):
|
||||
var db = m_parent_table.get_parent_database()
|
||||
var selected_table = db.get_table_by_id(gddb_types.e_prop_types_count - prop_type)
|
||||
print("GDDBTableEditor::on_edit_property(" + str(prop_id) + ", " + selected_table.get_table_name() + ", " + prop_name + ")")
|
||||
else:
|
||||
print("GDDBTableEditor::on_edit_property(" + str(prop_id) + ", " + gddb_globals.get_data_name(prop_type) + ", " + prop_name + ")")
|
||||
#"""
|
||||
# edit prop in the table
|
||||
m_parent_table.edit_prop(prop_id, prop_type, prop_name)
|
||||
|
||||
# refresh the prop name in data tab
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_header.get_child_count()):
|
||||
var prop = $tabs/data/scroll/data_holder/data_header.get_child(idx)
|
||||
if(prop.get_prop_id() == prop_id):
|
||||
prop.set_text(prop_name)
|
||||
|
||||
# update data type
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_container.get_child_count()):
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(idx)
|
||||
for jdx in range(0, row.get_child_count()):
|
||||
var cell = row.get_child(jdx)
|
||||
if(cell.get_prop_id() == prop_id):
|
||||
"""
|
||||
if(prop_type < gddb_types.e_prop_types_count):
|
||||
print("Prop type: " + gddb_globals.get_data_name(prop_type))
|
||||
else:
|
||||
print("Prop type: custom")
|
||||
"""
|
||||
cell.set_prop_type(prop_type)
|
||||
|
||||
emit_signal("set_dirty")
|
||||
|
||||
# called when a property is deleted
|
||||
func on_delete_property(prop_id : int) -> void:
|
||||
# print("GDDBTableEditor::on_delete_property(" + str(prop_id) + ")")
|
||||
var prop = m_parent_table.get_prop_by_id(prop_id)
|
||||
$delete_prop_dlg.set_prop_id(prop_id)
|
||||
$delete_prop_dlg.set_prop_name(prop.get_prop_name())
|
||||
$delete_prop_dlg.popup_centered()
|
||||
|
||||
# called when a property is deleted
|
||||
func on_confirm_delete_property() -> void:
|
||||
var prop_id = $delete_prop_dlg.get_prop_id()
|
||||
|
||||
# deletes a property from table; also all data by this property
|
||||
m_parent_table.delete_prop(prop_id)
|
||||
|
||||
# delete cells from data tab
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_container.get_child_count()):
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(idx)
|
||||
for jdx in range(0, row.get_child_count()):
|
||||
var cell = row.get_child(jdx)
|
||||
if(cell.get_prop_id() == prop_id):
|
||||
cell.disconnect("edit_data", self, "on_edit_data")
|
||||
cell.queue_free()
|
||||
break
|
||||
|
||||
# delete property from data tab
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_header.get_child_count()):
|
||||
var prop = $tabs/data/scroll/data_holder/data_header.get_child(idx)
|
||||
if(prop.get_prop_id() == prop_id):
|
||||
prop.queue_free()
|
||||
break
|
||||
|
||||
# delete prop from structure
|
||||
for idx in range(0, $tabs/structure/scroll/properties.get_child_count()):
|
||||
var prop = $tabs/structure/scroll/properties.get_child(idx)
|
||||
if(prop.get_prop_id() == prop_id):
|
||||
prop.queue_free()
|
||||
break
|
||||
|
||||
# refresh the add data button
|
||||
var props_count = m_parent_table.get_props_count()
|
||||
if(props_count == 0):
|
||||
$tabs/data/add_data_btn.set_disabled(true)
|
||||
|
||||
emit_signal("set_dirty")
|
||||
|
||||
# called when the property has autoincrement or not
|
||||
func on_enable_prop_autoincrement(prop_id : int, enable : bool) -> void :
|
||||
m_parent_table.enable_prop_autoincrement(prop_id, enable)
|
||||
emit_signal("set_dirty")
|
||||
refresh_autoincrement_props(prop_id, enable)
|
||||
|
||||
# reindex all data
|
||||
if(enable):
|
||||
for idx in range(0, $tabs/data/scroll/data_holder/data_container.get_child_count()):
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(idx)
|
||||
for jdx in range(0, row.get_child_count()):
|
||||
var cell = row.get_child(jdx)
|
||||
if(cell.get_prop_id() == prop_id):
|
||||
cell.set_text(str(idx + 1))
|
||||
|
||||
# called when edit data
|
||||
func on_edit_data(prop_id : int, row_idx : int, data : String) -> void:
|
||||
m_parent_table.edit_data(prop_id, row_idx, data)
|
||||
emit_signal("set_dirty")
|
||||
|
||||
# called when choosing a resource
|
||||
func on_choose_resource(prop_id : int, row_idx : int) -> void:
|
||||
# print("GDDBTableEditor::on_choose_resource(" + str(prop_id) + ", " + str(row_idx) + ")")
|
||||
$load_res_path_dlg.set_prop_id(prop_id)
|
||||
$load_res_path_dlg.set_row_idx(row_idx)
|
||||
$load_res_path_dlg.popup_centered()
|
||||
|
||||
# called when choosing a data
|
||||
func on_choose_data(prop_id : int, row_idx : int, prop_type : int) -> void:
|
||||
# print("GDDBTableEditor::on_choose_data(" + str(prop_id) + ", " + str(row_idx) + ", " + str(prop_type) + ")")
|
||||
$data_dlg.set_prop_id(prop_id)
|
||||
$data_dlg.set_row_idx(row_idx)
|
||||
var table_id = prop_type - gddb_types.e_prop_types_count
|
||||
var db = m_parent_table.get_parent_database()
|
||||
var tbl = db.get_table_by_id(table_id)
|
||||
$data_dlg.set_table(tbl)
|
||||
$data_dlg.popup_centered()
|
||||
|
||||
# called when choosing to edit string
|
||||
func on_edit_string(prop_id : int, row_idx : int, text : String) -> void:
|
||||
$edit_string_dlg.set_prop_id(prop_id)
|
||||
$edit_string_dlg.set_row_idx(row_idx)
|
||||
$edit_string_dlg.set_data_text(text)
|
||||
$edit_string_dlg.popup_centered()
|
||||
|
||||
# called when selecting a resource filepath
|
||||
func on_select_res_path(filepath : String) -> void:
|
||||
# print("GDDBTableEditor::on_select_res_path(" + filepath + ")")
|
||||
var prop_id = $load_res_path_dlg.get_prop_id()
|
||||
var row_idx = $load_res_path_dlg.get_row_idx()
|
||||
m_parent_table.edit_data(prop_id, row_idx, filepath)
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(row_idx)
|
||||
for idx in range(0, row.get_child_count()):
|
||||
var cell = row.get_child(idx)
|
||||
if(cell.get_prop_id() == prop_id):
|
||||
cell.set_text(filepath)
|
||||
|
||||
emit_signal("set_dirty")
|
||||
|
||||
# called when data from a table is choosen
|
||||
func on_select_data(prop_id : int, row_idx : int, data_row_idx : int, data : String) -> void:
|
||||
# set the data in the databes / table
|
||||
m_parent_table.edit_data(prop_id, row_idx, str(data_row_idx))
|
||||
|
||||
# fill in the interface cell with data
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(row_idx)
|
||||
for idx in range(0, row.get_child_count()):
|
||||
var cell = row.get_child(idx)
|
||||
if(cell.get_prop_id() == prop_id):
|
||||
cell.set_text(data)
|
||||
break
|
||||
|
||||
emit_signal("set_dirty")
|
||||
|
||||
# called when the text is edited
|
||||
func on_text_edited():
|
||||
var prop_id = $edit_string_dlg.get_prop_id()
|
||||
var row_idx = $edit_string_dlg.get_row_idx()
|
||||
var text_data = $edit_string_dlg.get_data_text()
|
||||
|
||||
var data = gddb_globals.handle_string(text_data)
|
||||
|
||||
# print("GDDBTableEditor::on_text_edited() - prop_id: " + str(prop_id) + ", row_idx: " + str(row_idx) + ", data: " + text_data)
|
||||
|
||||
m_parent_table.edit_data(prop_id, row_idx, data)
|
||||
|
||||
var row = $tabs/data/scroll/data_holder/data_container.get_child(row_idx)
|
||||
for idx in range(0, row.get_child_count()):
|
||||
var cell = row.get_child(idx)
|
||||
if(cell.get_prop_id() == prop_id):
|
||||
cell.set_text(text_data)
|
||||
break
|
||||
|
||||
emit_signal("set_dirty")
|
||||
@@ -1,161 +0,0 @@
|
||||
[gd_scene load_steps=16 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/error_dlg.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/load_res_path_dlg.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/table_editor.gd" type="Script" id=3]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/data_dlg.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/edit_string_dlg.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://addons/godot_db_manager/dlgs/delete_prop_dlg.tscn" type="PackedScene" id=6]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_18.tres" type="DynamicFont" id=7]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/gui.png" type="Texture" id=8]
|
||||
|
||||
[sub_resource type="AtlasTexture" id=1]
|
||||
atlas = ExtResource( 8 )
|
||||
region = Rect2( 2, 2, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=2]
|
||||
atlas = ExtResource( 8 )
|
||||
region = Rect2( 2, 54, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=3]
|
||||
atlas = ExtResource( 8 )
|
||||
region = Rect2( 2, 28, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=4]
|
||||
atlas = ExtResource( 8 )
|
||||
region = Rect2( 2, 2, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=5]
|
||||
atlas = ExtResource( 8 )
|
||||
region = Rect2( 2, 54, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=6]
|
||||
atlas = ExtResource( 8 )
|
||||
region = Rect2( 2, 28, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=7]
|
||||
atlas = ExtResource( 8 )
|
||||
region = Rect2( 132, 2, 24, 24 )
|
||||
|
||||
[node name="table" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ 584.0, 64.0, 70.0 ],
|
||||
"_edit_use_anchors_": false,
|
||||
"_edit_vertical_guides_": [ 1000.47 ]
|
||||
}
|
||||
|
||||
[node name="tabs" type="TabContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_fonts/font = ExtResource( 7 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="structure" type="Tabs" parent="tabs"]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 4.0
|
||||
margin_top = 40.0
|
||||
margin_right = -4.0
|
||||
margin_bottom = -4.0
|
||||
tab_close_display_policy = 2
|
||||
|
||||
[node name="header" type="HBoxContainer" parent="tabs/structure"]
|
||||
margin_right = 892.0
|
||||
margin_bottom = 24.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="new_property_btn" type="TextureButton" parent="tabs/structure/header"]
|
||||
margin_right = 24.0
|
||||
margin_bottom = 24.0
|
||||
texture_normal = SubResource( 1 )
|
||||
texture_pressed = SubResource( 2 )
|
||||
texture_hover = SubResource( 3 )
|
||||
|
||||
[node name="props_lbl" type="Label" parent="tabs/structure/header"]
|
||||
margin_left = 28.0
|
||||
margin_top = 1.0
|
||||
margin_right = 114.0
|
||||
margin_bottom = 23.0
|
||||
custom_fonts/font = ExtResource( 7 )
|
||||
text = "Properties:"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="scroll" type="ScrollContainer" parent="tabs/structure"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = 30.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="properties" type="VBoxContainer" parent="tabs/structure/scroll"]
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="data" type="Tabs" parent="tabs"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 4.0
|
||||
margin_top = 40.0
|
||||
margin_right = -4.0
|
||||
margin_bottom = -4.0
|
||||
tab_close_display_policy = 2
|
||||
|
||||
[node name="add_data_btn" type="TextureButton" parent="tabs/data"]
|
||||
margin_right = 24.0
|
||||
margin_bottom = 24.0
|
||||
disabled = true
|
||||
texture_normal = SubResource( 4 )
|
||||
texture_pressed = SubResource( 5 )
|
||||
texture_hover = SubResource( 6 )
|
||||
texture_disabled = SubResource( 7 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="scroll" type="ScrollContainer" parent="tabs/data"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = 38.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="data_holder" type="VBoxContainer" parent="tabs/data/scroll"]
|
||||
margin_bottom = 36.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="data_header" type="HBoxContainer" parent="tabs/data/scroll/data_holder"]
|
||||
margin_bottom = 32.0
|
||||
rect_min_size = Vector2( 0, 32 )
|
||||
rect_clip_content = true
|
||||
|
||||
[node name="data_container" type="VBoxContainer" parent="tabs/data/scroll/data_holder"]
|
||||
margin_top = 36.0
|
||||
margin_bottom = 36.0
|
||||
|
||||
[node name="error_dlg" parent="." instance=ExtResource( 1 )]
|
||||
visible = false
|
||||
|
||||
[node name="load_res_path_dlg" parent="." instance=ExtResource( 2 )]
|
||||
filters = PoolStringArray( "*.res, *.tres ; Godot resource file types", "*.scn, *.tscn, *escn ; Godot scene file types", "*.gd, *.cs, *.h, *.c, *.hpp, *.cpp ; Code file types", "*.shader ; Shader file types", "*.mat ; Material file types", "*.dae, *.gltf, *.obj, *.fbx ; Mesh file types", "*.anim ; Animation file types", "*.ttf, *.otf ; Font file types", "*.png, *.jpg, *.jpeg, *.tiff, *.tga, *.bmp, *.webp, *.gif, *.hdr ; Images file types", "*.snd, *.wav, *.ogg, *.mp3 ; Sound file types", "*.ogg, *.mpg, *.mpeg, *.avi, *.mov, *.mp4, *.webm ; Video file types", "*.txt, *.csv, *.json, *.xml, *.cfg, *.ini ; Text file types", "*.doc, *.docx, *.xls, *.xlsx, *.odt, *.ods, *.pdf ; Doc file types", "*.dat, *.raw ; Binary data file types" )
|
||||
|
||||
[node name="data_dlg" parent="." instance=ExtResource( 4 )]
|
||||
|
||||
[node name="edit_string_dlg" parent="." instance=ExtResource( 5 )]
|
||||
|
||||
[node name="delete_prop_dlg" parent="." instance=ExtResource( 6 )]
|
||||
visible = false
|
||||
@@ -1,67 +0,0 @@
|
||||
"""
|
||||
class GDDBTableItem
|
||||
"""
|
||||
|
||||
class_name GDDBTableItem
|
||||
|
||||
tool
|
||||
extends Control
|
||||
|
||||
signal select_item
|
||||
signal edit_table
|
||||
signal delete_table
|
||||
|
||||
var m_table_id = gddb_constants.c_invalid_id
|
||||
var m_table_name = ""
|
||||
|
||||
var m_is_selected = false
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
$select_btn.connect("pressed", self, "on_select_btn_pressed")
|
||||
$edit_table_btn.connect("pressed", self, "on_edit_table_btn_pressed")
|
||||
$delete_table_btn.connect("pressed", self, "on_delete_table_btn_pressed")
|
||||
$select.hide()
|
||||
|
||||
# sets the table id
|
||||
func set_table_id(id : int) -> void:
|
||||
m_table_id = id
|
||||
|
||||
# returns the table id
|
||||
func get_table_id() -> int:
|
||||
return m_table_id
|
||||
|
||||
func set_selected(select : bool) -> void :
|
||||
m_is_selected = select
|
||||
if(m_is_selected):
|
||||
$select.show()
|
||||
else:
|
||||
$select.hide()
|
||||
|
||||
func is_selected():
|
||||
return m_is_selected
|
||||
|
||||
# sets the table name
|
||||
func set_table_name(name : String) -> void:
|
||||
# print("GDDBTableItem::set_table_name(" + name + ")")
|
||||
m_table_name = name
|
||||
$table_name.set_text(m_table_name)
|
||||
|
||||
# returns the table name
|
||||
func get_table_name() -> String:
|
||||
return m_table_name
|
||||
|
||||
# called when the user presses the edit_table button
|
||||
func on_edit_table_btn_pressed():
|
||||
# print("GDDBTableItem::on_edit_table_btn_pressed")
|
||||
emit_signal("edit_table", m_table_id, m_table_name)
|
||||
|
||||
# called when the user presses the delete_table button
|
||||
func on_delete_table_btn_pressed():
|
||||
# print("GDDBTableItem::on_delete_table_btn_pressed")
|
||||
emit_signal("delete_table", m_table_id)
|
||||
|
||||
# called when select_btn is pressed
|
||||
func on_select_btn_pressed() -> void:
|
||||
# print("GDDBTableItem::on_select_btn_pressed()")
|
||||
emit_signal("select_item", m_table_id)
|
||||
@@ -1,109 +0,0 @@
|
||||
[gd_scene load_steps=11 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_18.tres" type="DynamicFont" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/gui.png" type="Texture" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/table_item.gd" type="Script" id=3]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/debug.png" type="Texture" id=4]
|
||||
|
||||
[sub_resource type="AtlasTexture" id=1]
|
||||
atlas = ExtResource( 2 )
|
||||
region = Rect2( 28, 2, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=2]
|
||||
atlas = ExtResource( 2 )
|
||||
region = Rect2( 28, 54, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=3]
|
||||
atlas = ExtResource( 2 )
|
||||
region = Rect2( 28, 28, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=4]
|
||||
atlas = ExtResource( 2 )
|
||||
region = Rect2( 54, 2, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=5]
|
||||
atlas = ExtResource( 2 )
|
||||
region = Rect2( 54, 54, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=6]
|
||||
atlas = ExtResource( 2 )
|
||||
region = Rect2( 54, 28, 24, 24 )
|
||||
|
||||
[node name="table_item" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.021
|
||||
margin_bottom = 0.399998
|
||||
rect_min_size = Vector2( 180, 34 )
|
||||
script = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ 34.0 ],
|
||||
"_edit_use_anchors_": false,
|
||||
"_edit_vertical_guides_": [ 170.0 ]
|
||||
}
|
||||
|
||||
[node name="dbg" type="NinePatchRect" parent="."]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
texture = ExtResource( 4 )
|
||||
region_rect = Rect2( 38, 38, 10, 10 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="select" type="NinePatchRect" parent="."]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
texture = ExtResource( 2 )
|
||||
region_rect = Rect2( 80, 6, 24, 4 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="table_name" type="Label" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_right = -6.10352e-05
|
||||
margin_bottom = -4.0
|
||||
rect_min_size = Vector2( 100, 0 )
|
||||
custom_fonts/font = ExtResource( 1 )
|
||||
text = "Table_999"
|
||||
valign = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="select_btn" type="TextureButton" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="edit_table_btn" type="TextureButton" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -56.0
|
||||
margin_top = 5.0
|
||||
margin_right = -32.0
|
||||
margin_bottom = -5.0
|
||||
texture_normal = SubResource( 1 )
|
||||
texture_pressed = SubResource( 2 )
|
||||
texture_hover = SubResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="delete_table_btn" type="TextureButton" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -28.0
|
||||
margin_top = 5.0
|
||||
margin_right = -4.0
|
||||
margin_bottom = -5.0
|
||||
texture_normal = SubResource( 4 )
|
||||
texture_pressed = SubResource( 5 )
|
||||
texture_hover = SubResource( 6 )
|
||||
@@ -1,195 +0,0 @@
|
||||
"""
|
||||
class GDDBTableProperty
|
||||
"""
|
||||
|
||||
class_name GDDBTableProperty
|
||||
|
||||
tool
|
||||
extends Control
|
||||
|
||||
signal delete_property
|
||||
signal edit_property
|
||||
signal enable_autoincrement
|
||||
|
||||
var m_prop_id : int = -1
|
||||
var m_prop_type : int = 0
|
||||
var m_prop_name : String = ""
|
||||
|
||||
var m_parent_table = null
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
$prop_name.connect("text_changed", self, "on_name_changed")
|
||||
|
||||
$prop_type.clear()
|
||||
for idx in range(0, gddb_types.e_prop_types_count):
|
||||
$prop_type.add_item(gddb_globals.get_data_name(idx), gddb_types.e_prop_type_bool + idx)
|
||||
$prop_type.select(0)
|
||||
|
||||
$prop_type.get_popup().connect("about_to_show", self, "on_about_to_show")
|
||||
$prop_type.connect("item_selected", self, "on_type_changed")
|
||||
|
||||
$delete_button.connect("pressed", self, "on_delete_button_pressed")
|
||||
|
||||
$autoincrement_btn.hide()
|
||||
$autoincrement_btn.connect("toggled", self, "on_set_autoincrement")
|
||||
|
||||
# setup property
|
||||
func setup(prop_id : int, prop_type : int, prop_name : String) -> void:
|
||||
"""
|
||||
if(prop_type < gddb_types.e_prop_types_count):
|
||||
print("GDDBTableProperty::setup(" + str(prop_id) + ", " + gddb_globals.get_data_name(prop_type) + ", " + prop_name + ")")
|
||||
else:
|
||||
var db = m_parent_table.get_parent_database()
|
||||
var table = db.get_table_by_id(prop_type - gddb_types.e_prop_types_count)
|
||||
print("GDDBTableProperty::setup(" + str(prop_id) + ", " + table.get_table_name() + ", " + prop_name + ")")
|
||||
#"""
|
||||
set_prop_id(prop_id)
|
||||
set_prop_type(prop_type)
|
||||
set_prop_name(prop_name)
|
||||
|
||||
# sets parent table
|
||||
func set_parent_table(table):
|
||||
#print("GDDBTableProperty::set_parent_table(" + str(table) + ")")
|
||||
m_parent_table = table
|
||||
var db = m_parent_table.get_parent_database()
|
||||
for idx in range(0, db.get_tables_count()):
|
||||
var tbl = db.get_table_at(idx)
|
||||
if(tbl == m_parent_table):
|
||||
continue
|
||||
$prop_type.add_item(tbl.get_table_name(), gddb_types.e_prop_types_count + tbl.get_table_id())
|
||||
|
||||
# sets proprty id
|
||||
func set_prop_id(prop_id : int) -> void:
|
||||
# print("GDDBTableProperty::set_prop_id(" + str(prop_id) + ")")
|
||||
m_prop_id = prop_id
|
||||
|
||||
# returns property id
|
||||
func get_prop_id() -> int:
|
||||
return m_prop_id
|
||||
|
||||
# sets property type
|
||||
func set_prop_type(prop_type : int) -> void:
|
||||
"""
|
||||
print("GDDBTableProperty::set_prop_type(" + str(prop_type) + ")")
|
||||
if(prop_type < gddb_types.e_prop_types_count):
|
||||
print("GDDBTableProperty::set_prop_type(" + gddb_globals.get_data_name(prop_type) + ")")
|
||||
else:
|
||||
var db = m_parent_table.get_parent_database()
|
||||
var table = db.get_table_by_id(prop_type - gddb_types.e_prop_types_count)
|
||||
print("GDDBTableProperty::set_prop_type(" + table.get_table_name() + ")")
|
||||
#"""
|
||||
#if(prop_type >= gddb_types.e_prop_types_count):
|
||||
# print("GDDBTableProperty::set_prop_type(" + str(prop_type) + ")")
|
||||
m_prop_type = prop_type
|
||||
select_current_prop()
|
||||
|
||||
if(m_prop_type == gddb_types.e_prop_type_int):
|
||||
$autoincrement_btn.show()
|
||||
var prop = m_parent_table.get_prop_by_id(m_prop_id)
|
||||
if(prop.has_autoincrement()):
|
||||
$autoincrement_btn.set_pressed(true)
|
||||
else:
|
||||
$autoincrement_btn.hide()
|
||||
|
||||
# selects current property
|
||||
func select_current_prop() -> void:
|
||||
if(m_prop_type < gddb_types.e_prop_types_count):
|
||||
$prop_type.select(m_prop_type)
|
||||
|
||||
# links property type to other tables
|
||||
func link():
|
||||
# print("GDDBTableProperty::link()")
|
||||
refill_list()
|
||||
if(m_prop_type >= gddb_types.e_prop_types_count):
|
||||
"""
|
||||
print("m_prop_id : " + str(m_prop_id))
|
||||
print("m_prop_type : " + str(m_prop_type))
|
||||
print("m_prop_name : " + m_prop_name)
|
||||
"""
|
||||
set_selection_by_id(m_prop_type)
|
||||
else:
|
||||
$prop_type.select(m_prop_type)
|
||||
|
||||
# returns property type
|
||||
func get_prop_type() -> int:
|
||||
return m_prop_type
|
||||
|
||||
# sets property name
|
||||
func set_prop_name(prop_name : String) -> void:
|
||||
# print("GDDBTableProperty::set_prop_name(" + prop_name + ")")
|
||||
m_prop_name = prop_name
|
||||
$prop_name.set_text(m_prop_name)
|
||||
|
||||
# returns property name
|
||||
func get_prop_name() -> String:
|
||||
return m_prop_name
|
||||
|
||||
# called everytime the name of the property is changed
|
||||
func on_name_changed(new_text : String) -> void:
|
||||
m_prop_name = new_text
|
||||
emit_signal("edit_property", m_prop_id, m_prop_type, m_prop_name)
|
||||
|
||||
# called when the popup from option button is about to be shown
|
||||
func on_about_to_show():
|
||||
var selected_id = $prop_type.get_selected_id()
|
||||
# print("GDDBTableProperty::on_about_to_show() - " + str(selected_id))
|
||||
|
||||
refill_list()
|
||||
set_selection_by_id(selected_id)
|
||||
|
||||
# refills the list
|
||||
func refill_list() -> void :
|
||||
$prop_type.clear()
|
||||
for idx in range(0, gddb_types.e_prop_types_count):
|
||||
$prop_type.add_item(gddb_globals.get_data_name(idx), gddb_types.e_prop_type_bool + idx)
|
||||
|
||||
if(null != m_parent_table):
|
||||
var db = m_parent_table.get_parent_database()
|
||||
for idx in range(0, db.get_tables_count()):
|
||||
var table = db.get_table_at(idx)
|
||||
if(table == m_parent_table):
|
||||
continue
|
||||
"""
|
||||
print("GDDBTableProperty::refill_list - Add:")
|
||||
print("table id: " + str(table.get_table_id()))
|
||||
print("table name: " + table.get_table_name())
|
||||
#"""
|
||||
# print("GDDBTableProperty::prop_type.add_item(" + table.get_table_name() + ", " + str(gddb_types.e_prop_types_count + table.get_table_id()) + ")" )
|
||||
$prop_type.add_item(table.get_table_name(), gddb_types.e_prop_types_count + table.get_table_id())
|
||||
# $prop_type.select(selected_idx)
|
||||
|
||||
# sets selection
|
||||
func set_selection_by_id(selected_id : int) -> void :
|
||||
# print("GDDBTableProperty::set_selection_by_id(" + str(selected_id) + ")")
|
||||
for idx in range(0, $prop_type.get_item_count()):
|
||||
if($prop_type.get_item_id(idx) == selected_id):
|
||||
$prop_type.select(idx)
|
||||
break
|
||||
|
||||
func on_set_autoincrement(enable : bool) -> void:
|
||||
# print("GDDBTableProperty::on_set_autoincrement(" + str(enable) + ") - " + str(m_prop_id))
|
||||
emit_signal("enable_autoincrement", m_prop_id, enable)
|
||||
|
||||
# called everytime the type of the property is changed
|
||||
func on_type_changed(option_idx : int) -> void:
|
||||
var option_id = $prop_type.get_item_id(option_idx)
|
||||
"""
|
||||
print("GDDBTableProperty::on_type_changed(" + str(option_idx) + ")")
|
||||
print("option_id = " + str(option_id))
|
||||
if(option_id >= gddb_types.e_prop_types_count):
|
||||
print("GDDBTableProperty::on_type_changed(" + str(option_id) + ")")
|
||||
else:
|
||||
print("GDDBTableProperty::on_type_changed(" + gddb_globals.get_data_name(option_id) + ")")
|
||||
#"""
|
||||
m_prop_type = option_id
|
||||
$autoincrement_btn.set_pressed(false)
|
||||
if(m_prop_type == gddb_types.e_prop_type_int):
|
||||
$autoincrement_btn.show()
|
||||
else:
|
||||
$autoincrement_btn.hide()
|
||||
emit_signal("edit_property", m_prop_id, m_prop_type, m_prop_name)
|
||||
|
||||
# called when the delete property button is pressed
|
||||
func on_delete_button_pressed() -> void:
|
||||
emit_signal("delete_property", m_prop_id)
|
||||
@@ -1,89 +0,0 @@
|
||||
[gd_scene load_steps=7 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/gui.png" type="Texture" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/table_property.gd" type="Script" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_18.tres" type="DynamicFont" id=3]
|
||||
|
||||
[sub_resource type="AtlasTexture" id=1]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 54, 2, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=2]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 54, 54, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=3]
|
||||
atlas = ExtResource( 1 )
|
||||
region = Rect2( 54, 28, 24, 24 )
|
||||
|
||||
[node name="table_property" type="Control"]
|
||||
anchor_right = 1.0
|
||||
margin_bottom = 15.36
|
||||
rect_min_size = Vector2( 900, 32 )
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ 32.0 ],
|
||||
"_edit_use_anchors_": true
|
||||
}
|
||||
|
||||
[node name="delete_button" type="TextureButton" parent="."]
|
||||
margin_left = 3.0
|
||||
margin_top = 4.0
|
||||
margin_right = 27.0
|
||||
margin_bottom = 28.0
|
||||
texture_normal = SubResource( 1 )
|
||||
texture_pressed = SubResource( 2 )
|
||||
texture_hover = SubResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="prop_name_label" type="Label" parent="."]
|
||||
margin_left = 28.0
|
||||
margin_top = 2.0
|
||||
margin_right = 97.0
|
||||
margin_bottom = 24.0
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = " Name:"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="prop_name" type="LineEdit" parent="."]
|
||||
margin_left = 109.0
|
||||
margin_right = 409.0
|
||||
margin_bottom = 32.0
|
||||
rect_min_size = Vector2( 300, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="type_label" type="Label" parent="."]
|
||||
margin_left = 413.0
|
||||
margin_top = 2.0
|
||||
margin_right = 473.0
|
||||
margin_bottom = 24.0
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = " Type:"
|
||||
|
||||
[node name="prop_type" type="OptionButton" parent="."]
|
||||
margin_left = 485.0
|
||||
margin_right = 735.0
|
||||
margin_bottom = 32.0
|
||||
rect_min_size = Vector2( 250, 0 )
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "Bool"
|
||||
items = [ "Bool", null, false, 0, null, "Integer", null, false, 1, null, "Float", null, false, 2, null, "String", null, false, 3, null, "Resource", null, false, 4, null ]
|
||||
selected = 0
|
||||
|
||||
[node name="autoincrement_btn" type="CheckBox" parent="."]
|
||||
visible = false
|
||||
margin_left = 740.0
|
||||
margin_right = 891.0
|
||||
margin_bottom = 32.0
|
||||
custom_fonts/font = ExtResource( 3 )
|
||||
text = "Auto increment"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
"""
|
||||
class GDDBTablesHeader
|
||||
"""
|
||||
|
||||
class_name GDDBTablesHeader
|
||||
|
||||
tool
|
||||
extends Control
|
||||
|
||||
signal add_table
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
$add_table_btn.connect("pressed", self, "on_add_table_btn_pressed")
|
||||
|
||||
func on_add_table_btn_pressed():
|
||||
emit_signal("add_table")
|
||||
@@ -1,65 +0,0 @@
|
||||
[gd_scene load_steps=7 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/fnt/roboto_20.tres" type="DynamicFont" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/tables_header.gd" type="Script" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/gui.png" type="Texture" id=3]
|
||||
|
||||
[sub_resource type="AtlasTexture" id=1]
|
||||
atlas = ExtResource( 3 )
|
||||
region = Rect2( 2, 2, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=2]
|
||||
atlas = ExtResource( 3 )
|
||||
region = Rect2( 2, 54, 24, 24 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=3]
|
||||
atlas = ExtResource( 3 )
|
||||
region = Rect2( 2, 28, 24, 24 )
|
||||
|
||||
[node name="tables_header" type="Control"]
|
||||
anchor_right = 0.188889
|
||||
anchor_bottom = 0.019
|
||||
margin_right = 6.10352e-05
|
||||
margin_bottom = -0.4
|
||||
rect_min_size = Vector2( 170, 30 )
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": true,
|
||||
"_edit_vertical_guides_": [ 170.0 ]
|
||||
}
|
||||
|
||||
[node name="add_table_btn" type="TextureButton" parent="."]
|
||||
margin_left = 2.0
|
||||
margin_top = 2.0
|
||||
margin_right = 26.0
|
||||
margin_bottom = 26.0
|
||||
texture_normal = SubResource( 1 )
|
||||
texture_pressed = SubResource( 2 )
|
||||
texture_hover = SubResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="tables_lbl" type="Label" parent="."]
|
||||
anchor_left = 0.165
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.8
|
||||
margin_left = -0.0500259
|
||||
margin_right = -0.000152588
|
||||
custom_fonts/font = ExtResource( 1 )
|
||||
text = "Tables "
|
||||
align = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="line" type="NinePatchRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = 29.0
|
||||
margin_right = -0.000152588
|
||||
texture = ExtResource( 3 )
|
||||
region_rect = Rect2( 80, 2, 24, 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
"""
|
||||
class GDDBTablesList
|
||||
"""
|
||||
|
||||
class_name GDDBTablesList
|
||||
|
||||
tool
|
||||
extends Control
|
||||
|
||||
signal resize_tables_list
|
||||
|
||||
signal add_table
|
||||
signal edit_table_name
|
||||
signal delete_table
|
||||
signal select_table
|
||||
|
||||
var m_tables = []
|
||||
|
||||
var m_mouse_pos_pressed : Vector2 = Vector2()
|
||||
var m_mouse_pressed : bool = false
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
m_mouse_pos_pressed = Vector2()
|
||||
m_mouse_pressed = false
|
||||
|
||||
$tables_header.connect("add_table", self, "on_add_table")
|
||||
|
||||
# called when the node gets an input
|
||||
func _input(event : InputEvent) -> void :
|
||||
if(!gddb_globals.is_interface_active()):
|
||||
return
|
||||
|
||||
var evLocal = $resize_ctrl.make_input_local(event)
|
||||
|
||||
if event is InputEventMouseButton :
|
||||
if(event.button_index == BUTTON_LEFT):
|
||||
if(event.pressed):
|
||||
var rect = Rect2(Vector2(0, 0), $resize_ctrl.get_size())
|
||||
var inside = rect.has_point(evLocal.position)
|
||||
if(inside):
|
||||
m_mouse_pressed = true
|
||||
m_mouse_pos_pressed = evLocal.position
|
||||
else:
|
||||
m_mouse_pressed = false
|
||||
|
||||
elif event is InputEventMouseMotion :
|
||||
if(m_mouse_pressed):
|
||||
var diff_x = evLocal.position.x - m_mouse_pos_pressed.x
|
||||
emit_signal("resize_tables_list", diff_x)
|
||||
|
||||
# custom resizing the tables list
|
||||
func resize_content(size : Vector2) -> void :
|
||||
set_size(size)
|
||||
|
||||
# I have no idea why I need to do this; this should be done automatically
|
||||
var content_size = $tables_container/tables.get_size()
|
||||
content_size.x = size.x
|
||||
$tables_container/tables.set_custom_minimum_size(content_size)
|
||||
|
||||
# Called when the user presses the "add_table" button from the tables_list/header
|
||||
func on_add_table() -> void :
|
||||
# print("GDDBTablesList::on_add_table()")
|
||||
emit_signal("add_table")
|
||||
|
||||
# creates a table
|
||||
func create_table(db_table : Object, select_table : bool = true) -> void:
|
||||
# print("GDDBTablesList::create_table(" + str(db_table) + ")")
|
||||
var table = load(gddb_constants.c_addon_main_path + "table_item.tscn").instance()
|
||||
var table_id = db_table.get_table_id()
|
||||
table.set_table_id(table_id)
|
||||
table.set_table_name(db_table.get_table_name())
|
||||
table.connect("select_item", self, "on_select_item")
|
||||
table.connect("edit_table", self, "on_edit_table_name")
|
||||
table.connect("delete_table", self, "on_delete_table")
|
||||
m_tables.push_back(table)
|
||||
$tables_container/tables.add_child(table)
|
||||
if(select_table):
|
||||
select_item_by_id(table_id)
|
||||
|
||||
# Called when the user presses the "edit_table" button from the tables_list/table
|
||||
func on_edit_table_name(table_id : int, table_name : String) -> void:
|
||||
# print("GDDBTablesList::on_edit_table_name(" + str(table_id) + ", " + table_name + ")")
|
||||
emit_signal("edit_table_name", table_id, table_name)
|
||||
|
||||
# Called when the user presses the "delete_table" button from the tables_list/table
|
||||
func on_delete_table(table_id : int) -> void:
|
||||
# print("GDDBTablesList::on_delete_table(" + str(table_id) + ")")
|
||||
emit_signal("delete_table", table_id)
|
||||
|
||||
# edits the table name
|
||||
func edit_table_name(table_id: int, table_name : String) -> void:
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].get_table_id() == table_id):
|
||||
m_tables[idx].set_table_name(table_name)
|
||||
break
|
||||
|
||||
# deletes a table from the list
|
||||
func delete_table(table_id : int) -> void:
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].get_table_id() == table_id):
|
||||
$tables_container/tables.remove_child(m_tables[idx])
|
||||
m_tables.remove(idx)
|
||||
break
|
||||
|
||||
# called when the user presses an item
|
||||
func on_select_item(table_id : int) -> void:
|
||||
# print("GDDBTablesList::on_select_item(" + str(table_id) + ")")
|
||||
select_item_by_id(table_id)
|
||||
emit_signal("select_table", table_id)
|
||||
|
||||
# select an item by index
|
||||
func select_item_at(table_idx : int) -> void:
|
||||
for idx in range(0, m_tables.size()):
|
||||
m_tables[idx].set_selected(idx == table_idx)
|
||||
|
||||
# select an item by id
|
||||
func select_item_by_id(table_id : int) -> void:
|
||||
# print("GDDBTablesList::select_item_by_id(" + str(table_id) + ")")
|
||||
for idx in range(0, m_tables.size()):
|
||||
m_tables[idx].set_selected(m_tables[idx].get_table_id() == table_id)
|
||||
|
||||
# returns the selected element
|
||||
func get_selected_item():
|
||||
for idx in range(0, m_tables.size()):
|
||||
if(m_tables[idx].is_selected()):
|
||||
return m_tables[idx]
|
||||
print("ERROR: GDDBTablesList::get_selected_item() - there is no selected element")
|
||||
return null
|
||||
@@ -1,60 +0,0 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_db_manager/tables_list.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_db_manager/tables_header.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://addons/godot_db_manager/debug/dbg.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://addons/godot_db_manager/assets/tex/gui.png" type="Texture" id=4]
|
||||
|
||||
[node name="tables_list" type="Control"]
|
||||
anchor_right = 0.2
|
||||
anchor_bottom = 1.0
|
||||
margin_right = -9.99991
|
||||
rect_min_size = Vector2( 180, 225 )
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ 29.9686, 584.0 ],
|
||||
"_edit_use_anchors_": false,
|
||||
"_edit_vertical_guides_": [ 180.0 ]
|
||||
}
|
||||
|
||||
[node name="tables_header" parent="." instance=ExtResource( 2 )]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = -9.15527e-05
|
||||
margin_bottom = 30.0
|
||||
rect_min_size = Vector2( 180, 30 )
|
||||
|
||||
[node name="tables_container" type="ScrollContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = 32.0
|
||||
rect_min_size = Vector2( 180, 0 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="tables" type="VBoxContainer" parent="tables_container"]
|
||||
rect_clip_content = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="resize_ctrl" type="NinePatchRect" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -3.0
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 15
|
||||
texture = ExtResource( 4 )
|
||||
region_rect = Rect2( 80, 12, 24, 24 )
|
||||
patch_margin_left = 1
|
||||
patch_margin_top = 1
|
||||
patch_margin_right = 1
|
||||
patch_margin_bottom = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="dbg" parent="." instance=ExtResource( 3 )]
|
||||
visible = false
|
||||
@@ -1,14 +1,15 @@
|
||||
# Copyright © 2020 Hugo Locurcio and contributors - MIT License
|
||||
# See `LICENSE.md` included in the source distribution for details.
|
||||
extends CPUParticles
|
||||
class_name LODCPUParticles, "lod_cpu_particles.svg"
|
||||
@icon("res://addons/lod/lod_cpu_particles.svg")
|
||||
class_name LODCPUParticles
|
||||
extends CPUParticles3D
|
||||
|
||||
# If `false`, LOD won't update anymore. This can be used for performance comparison
|
||||
# purposes.
|
||||
export var enable_lod := true
|
||||
@export var enable_lod := true
|
||||
|
||||
# The maximum particle emitting distance in units. Past this distance, particles will no longer emit.
|
||||
export(float, 0.0, 1000.0, 0.1) var max_emit_distance := 50
|
||||
@export var max_emit_distance := 50 # (float, 0.0, 1000.0, 0.1)
|
||||
|
||||
# The rate at which LODs will be updated (in seconds). Lower values are more reactive
|
||||
# but use more CPU, which is especially noticeable with large amounts of LOD-enabled nodes.
|
||||
@@ -22,7 +23,7 @@ var refresh_rate := 0.25
|
||||
# Positive values will decrease the detail level and improve performance.
|
||||
# Negative values will improve visual appearance at the cost of performance.
|
||||
# This can overridden by setting the project setting `lod/bias`.
|
||||
var lod_bias := 0.0
|
||||
var lod_distance_bias := 0.0
|
||||
|
||||
# The internal refresh timer.
|
||||
var timer := 0.0
|
||||
@@ -30,13 +31,13 @@ var timer := 0.0
|
||||
|
||||
func _ready() -> void:
|
||||
if ProjectSettings.has_setting("lod/particle_bias"):
|
||||
lod_bias = ProjectSettings.get_setting("lod/particle_bias")
|
||||
lod_distance_bias = ProjectSettings.get_setting("lod/particle_bias")
|
||||
if ProjectSettings.has_setting("lod/refresh_rate"):
|
||||
refresh_rate = ProjectSettings.get_setting("lod/refresh_rate")
|
||||
|
||||
# Add random jitter to the timer to ensure LODs don't all swap at the same time.
|
||||
randomize()
|
||||
timer += rand_range(0, refresh_rate)
|
||||
timer += randf_range(0, refresh_rate)
|
||||
|
||||
# Despite LOD not being related to physics, we chose to run in `_physics_process()`
|
||||
# to minimize the amount of method calls per second (and therefore decrease CPU usage).
|
||||
@@ -45,7 +46,7 @@ func _physics_process(delta: float) -> void:
|
||||
return
|
||||
|
||||
# We need a camera to do the rest.
|
||||
var camera := get_viewport().get_camera()
|
||||
var camera := get_viewport().get_camera_3d()
|
||||
if camera == null:
|
||||
return
|
||||
|
||||
@@ -55,5 +56,5 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
timer = 0.0
|
||||
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_bias
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_distance_bias
|
||||
emitting = distance < max_emit_distance
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bgn0l4r2ydecj
|
||||
@@ -1,8 +1,9 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/lod_cpu_particles.svg-b3ece84e0440c5d32851b9105345db21.stex"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://27ju1od2xllu"
|
||||
path="res://.godot/imported/lod_cpu_particles.svg-b3ece84e0440c5d32851b9105345db21.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
@@ -10,25 +11,33 @@ metadata={
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/lod/lod_cpu_particles.svg"
|
||||
dest_files=[ "res://.import/lod_cpu_particles.svg-b3ece84e0440c5d32851b9105345db21.stex" ]
|
||||
dest_files=["res://.godot/imported/lod_cpu_particles.svg-b3ece84e0440c5d32851b9105345db21.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
# Copyright © 2020 Hugo Locurcio and contributors - MIT License
|
||||
# See `LICENSE.md` included in the source distribution for details.
|
||||
extends OmniLight
|
||||
class_name LODOmniLight, "lod_omni_light.svg"
|
||||
@icon("res://addons/lod/lod_omni_light.svg")
|
||||
class_name LODOmniLight
|
||||
extends OmniLight3D
|
||||
|
||||
# If `false`, LOD won't update anymore. This can be used for performance comparison
|
||||
# purposes.
|
||||
export var enable_lod := true
|
||||
@export var enable_lod := true
|
||||
|
||||
# The maximum shadow distance in units. Past this distance, the shadow will be disabled.
|
||||
export(float, 0.0, 1000.0, 0.1) var shadow_max_distance := 25
|
||||
@export var shadow_max_distance := 25 # (float, 0.0, 1000.0, 0.1)
|
||||
|
||||
# The distance factor at which the shadow starts fading.
|
||||
# A value of 0.0 will result in the smoothest transition whereas a value of 1.0 disables fading.
|
||||
export(float, 0.0, 1.0, 0.1) var shadow_fade_start := 0.8
|
||||
@export var shadow_fade_start := 0.8 # (float, 0.0, 1.0, 0.1)
|
||||
|
||||
# The maximum shadow distance in units. Past this distance, the light will be hidden.
|
||||
export(float, 0.0, 1000.0, 0.1) var light_max_distance := 50
|
||||
@export var light_max_distance := 50 # (float, 0.0, 1000.0, 0.1)
|
||||
|
||||
# The distance factor at which the light starts fading.
|
||||
# A value of 0.0 will result in the smoothest transition whereas a value of 1.0 disables fading.
|
||||
export(float, 0.0, 1.0, 0.1) var light_fade_start := 0.8
|
||||
@export var light_fade_start := 0.8 # (float, 0.0, 1.0, 0.1)
|
||||
|
||||
# The rate at which LODs will be updated (in seconds). Lower values are more reactive
|
||||
# but use more CPU, which is especially noticeable with large amounts of LOD-enabled nodes.
|
||||
@@ -35,7 +36,7 @@ var refresh_rate := 0.05
|
||||
# Positive values will decrease the detail level and improve performance.
|
||||
# Negative values will improve visual appearance at the cost of performance.
|
||||
# This can overridden by setting the project setting `lod/bias`.
|
||||
var lod_bias := 0.0
|
||||
var lod_distance_bias := 0.0
|
||||
|
||||
# The internal refresh timer.
|
||||
var timer := 0.0
|
||||
@@ -46,13 +47,13 @@ var base_light_energy := light_energy
|
||||
|
||||
func _ready() -> void:
|
||||
if ProjectSettings.has_setting("lod/light_bias"):
|
||||
lod_bias = ProjectSettings.get_setting("lod/light_bias")
|
||||
lod_distance_bias = ProjectSettings.get_setting("lod/light_bias")
|
||||
if ProjectSettings.has_setting("lod/light_refresh_rate"):
|
||||
refresh_rate = ProjectSettings.get_setting("lod/light_refresh_rate")
|
||||
|
||||
# Add random jitter to the timer to ensure LODs don't all swap at the same time.
|
||||
randomize()
|
||||
timer += rand_range(0, refresh_rate)
|
||||
timer += randf_range(0, refresh_rate)
|
||||
|
||||
# Despite LOD not being related to physics, we chose to run in `_physics_process()`
|
||||
# to minimize the amount of method calls per second (and therefore decrease CPU usage).
|
||||
@@ -61,7 +62,7 @@ func _physics_process(delta: float) -> void:
|
||||
return
|
||||
|
||||
# We need a camera to do the rest.
|
||||
var camera := get_viewport().get_camera()
|
||||
var camera := get_viewport().get_camera_3d()
|
||||
if camera == null:
|
||||
return
|
||||
|
||||
@@ -71,7 +72,7 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
timer = 0.0
|
||||
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_bias
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_distance_bias
|
||||
|
||||
visible = distance < light_max_distance
|
||||
var light_fade_start_distance := light_max_distance * light_fade_start
|
||||
@@ -82,11 +83,3 @@ func _physics_process(delta: float) -> void:
|
||||
light_energy = base_light_energy
|
||||
|
||||
shadow_enabled = distance < shadow_max_distance
|
||||
var shadow_fade_start_distance := shadow_max_distance * shadow_fade_start
|
||||
var shadow_value: float
|
||||
if distance > shadow_fade_start_distance:
|
||||
shadow_value = min(1, (distance - shadow_fade_start_distance) / (shadow_max_distance - shadow_fade_start_distance))
|
||||
else:
|
||||
# We're close enough to the light to show its shadow at full darkness.
|
||||
shadow_value = 0.0
|
||||
shadow_color = Color(shadow_value, shadow_value, shadow_value)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://d30dj8px8hj0l
|
||||
@@ -1,8 +1,9 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/lod_omni_light.svg-72b7ec907b4f0e08e3154232a03aab77.stex"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://mx6063qws57r"
|
||||
path="res://.godot/imported/lod_omni_light.svg-72b7ec907b4f0e08e3154232a03aab77.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
@@ -10,25 +11,33 @@ metadata={
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/lod/lod_omni_light.svg"
|
||||
dest_files=[ "res://.import/lod_omni_light.svg-72b7ec907b4f0e08e3154232a03aab77.stex" ]
|
||||
dest_files=["res://.godot/imported/lod_omni_light.svg-72b7ec907b4f0e08e3154232a03aab77.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# Copyright © 2020 Hugo Locurcio and contributors - MIT License
|
||||
# See `LICENSE.md` included in the source distribution for details.
|
||||
extends Particles
|
||||
class_name LODParticles, "lod_particles.svg"
|
||||
@icon("res://addons/lod/lod_particles.svg")
|
||||
class_name LODParticles
|
||||
extends GPUParticles3D
|
||||
|
||||
# If `false`, LOD won't update anymore. This can be used for performance comparison
|
||||
# purposes.
|
||||
export var enable_lod := true
|
||||
@export var enable_lod := true
|
||||
|
||||
# The maximum particle emitting distance in units. Past this distance, particles will no longer emit.
|
||||
export(float, 0.0, 1000.0, 0.1) var max_emit_distance := 50
|
||||
@export var max_emit_distance := 50 # (float, 0.0, 1000.0, 0.1)
|
||||
|
||||
# The rate at which LODs will be updated (in seconds). Lower values are more reactive
|
||||
# but use more CPU, which is especially noticeable with large amounts of LOD-enabled nodes.
|
||||
@@ -22,7 +23,7 @@ var refresh_rate := 0.25
|
||||
# Positive values will decrease the detail level and improve performance.
|
||||
# Negative values will improve visual appearance at the cost of performance.
|
||||
# This can overridden by setting the project setting `lod/bias`.
|
||||
var lod_bias := 0.0
|
||||
var lod_distance_bias := 0.0
|
||||
|
||||
# The internal refresh timer.
|
||||
var timer := 0.0
|
||||
@@ -30,13 +31,13 @@ var timer := 0.0
|
||||
|
||||
func _ready() -> void:
|
||||
if ProjectSettings.has_setting("lod/particle_bias"):
|
||||
lod_bias = ProjectSettings.get_setting("lod/particle_bias")
|
||||
lod_distance_bias = ProjectSettings.get_setting("lod/particle_bias")
|
||||
if ProjectSettings.has_setting("lod/refresh_rate"):
|
||||
refresh_rate = ProjectSettings.get_setting("lod/refresh_rate")
|
||||
|
||||
# Add random jitter to the timer to ensure LODs don't all swap at the same time.
|
||||
randomize()
|
||||
timer += rand_range(0, refresh_rate)
|
||||
timer += randf_range(0, refresh_rate)
|
||||
|
||||
# Despite LOD not being related to physics, we chose to run in `_physics_process()`
|
||||
# to minimize the amount of method calls per second (and therefore decrease CPU usage).
|
||||
@@ -45,7 +46,7 @@ func _physics_process(delta: float) -> void:
|
||||
return
|
||||
|
||||
# We need a camera to do the rest.
|
||||
var camera := get_viewport().get_camera()
|
||||
var camera := get_viewport().get_camera_3d()
|
||||
if camera == null:
|
||||
return
|
||||
|
||||
@@ -55,5 +56,5 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
timer = 0.0
|
||||
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_bias
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_distance_bias
|
||||
emitting = distance < max_emit_distance
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://165j0dlh8l4w
|
||||
@@ -1,8 +1,9 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/lod_particles.svg-86d5ee48cd8c5d9e3cfcd6fa66432a55.stex"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c6x1ooubmx3ll"
|
||||
path="res://.godot/imported/lod_particles.svg-86d5ee48cd8c5d9e3cfcd6fa66432a55.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
@@ -10,25 +11,33 @@ metadata={
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/lod/lod_particles.svg"
|
||||
dest_files=[ "res://.import/lod_particles.svg-86d5ee48cd8c5d9e3cfcd6fa66432a55.stex" ]
|
||||
dest_files=["res://.godot/imported/lod_particles.svg-86d5ee48cd8c5d9e3cfcd6fa66432a55.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
||||
+12
-11
@@ -1,21 +1,22 @@
|
||||
# Copyright © 2020 Hugo Locurcio and contributors - MIT License
|
||||
# See `LICENSE.md` included in the source distribution for details.
|
||||
extends Spatial
|
||||
class_name LODSpatial, "lod_spatial.svg"
|
||||
@icon("res://addons/lod/lod_spatial.svg")
|
||||
class_name LODSpatial
|
||||
extends Node3D
|
||||
|
||||
# If `false`, LOD won't update anymore. This can be used for performance comparison
|
||||
# purposes.
|
||||
export var enable_lod := true
|
||||
@export var enable_lod := true
|
||||
|
||||
# The maximum LOD 0 (high quality) distance in units.
|
||||
export(float, 0.0, 1000.0, 0.1) var lod_0_max_distance := 10
|
||||
@export var lod_0_max_distance := 10 # (float, 0.0, 1000.0, 0.1)
|
||||
|
||||
# The maximum LOD 1 (medium quality) distance in units.
|
||||
export(float, 0.0, 1000.0, 0.1) var lod_1_max_distance := 25
|
||||
@export var lod_1_max_distance := 25 # (float, 0.0, 1000.0, 0.1)
|
||||
|
||||
# The maximum LOD 2 (low quality) distance in units.
|
||||
# Past this distance, all LOD variants are hidden.
|
||||
export(float, 0.0, 1000.0, 0.1) var lod_2_max_distance := 100
|
||||
@export var lod_2_max_distance := 100 # (float, 0.0, 1000.0, 0.1)
|
||||
|
||||
# The rate at which LODs will be updated (in seconds). Lower values are more reactive
|
||||
# but use more CPU, which is especially noticeable with large amounts of LOD-enabled nodes.
|
||||
@@ -29,7 +30,7 @@ var refresh_rate := 0.25
|
||||
# Positive values will decrease the detail level and improve performance.
|
||||
# Negative values will improve visual appearance at the cost of performance.
|
||||
# This can overridden by setting the project setting `lod/bias`.
|
||||
var lod_bias := 0.0
|
||||
var lod_distance_bias := 0.0
|
||||
|
||||
# The internal refresh timer.
|
||||
var timer := 0.0
|
||||
@@ -37,13 +38,13 @@ var timer := 0.0
|
||||
|
||||
func _ready() -> void:
|
||||
if ProjectSettings.has_setting("lod/spatial_bias"):
|
||||
lod_bias = ProjectSettings.get_setting("lod/spatial_bias")
|
||||
lod_distance_bias = ProjectSettings.get_setting("lod/spatial_bias")
|
||||
if ProjectSettings.has_setting("lod/refresh_rate"):
|
||||
refresh_rate = ProjectSettings.get_setting("lod/refresh_rate")
|
||||
|
||||
# Add random jitter to the timer to ensure LODs don't all swap at the same time.
|
||||
randomize()
|
||||
timer += rand_range(0, refresh_rate)
|
||||
timer += randf_range(0, refresh_rate)
|
||||
|
||||
|
||||
# Despite LOD not being related to physics, we chose to run in `_physics_process()`
|
||||
@@ -53,7 +54,7 @@ func _physics_process(delta: float) -> void:
|
||||
return
|
||||
|
||||
# We need a camera to do the rest.
|
||||
var camera := get_viewport().get_camera()
|
||||
var camera := get_viewport().get_camera_3d()
|
||||
if camera == null:
|
||||
return
|
||||
|
||||
@@ -63,7 +64,7 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
timer = 0.0
|
||||
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_bias
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_distance_bias
|
||||
# The LOD level to choose (lower is more detailed).
|
||||
var lod: int
|
||||
if distance < lod_0_max_distance:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://fnay4dhox0y7
|
||||
@@ -1,8 +1,9 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/lod_spatial.svg-0f291da571b0a5b87fdce289c6370d71.stex"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://drwqorwwfwjut"
|
||||
path="res://.godot/imported/lod_spatial.svg-0f291da571b0a5b87fdce289c6370d71.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
@@ -10,25 +11,33 @@ metadata={
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/lod/lod_spatial.svg"
|
||||
dest_files=[ "res://.import/lod_spatial.svg-0f291da571b0a5b87fdce289c6370d71.stex" ]
|
||||
dest_files=["res://.godot/imported/lod_spatial.svg-0f291da571b0a5b87fdce289c6370d71.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
# Copyright © 2020 Hugo Locurcio and contributors - MIT License
|
||||
# See `LICENSE.md` included in the source distribution for details.
|
||||
extends SpotLight
|
||||
class_name LODSpotLight, "lod_spot_light.svg"
|
||||
@icon("res://addons/lod/lod_spot_light.svg")
|
||||
class_name LODSpotLight
|
||||
extends SpotLight3D
|
||||
|
||||
# If `false`, LOD won't update anymore. This can be used for performance comparison
|
||||
# purposes.
|
||||
export var enable_lod := true
|
||||
@export var enable_lod := true
|
||||
|
||||
# The maximum shadow distance in units. Past this distance, the shadow will be disabled.
|
||||
export(float, 0.0, 1000.0, 0.1) var shadow_max_distance := 25
|
||||
@export var shadow_max_distance := 25 # (float, 0.0, 1000.0, 0.1)
|
||||
|
||||
# The distance factor at which the shadow starts fading.
|
||||
# A value of 0.0 will result in the smoothest transition whereas a value of 1.0 disables fading.
|
||||
export(float, 0.0, 1.0, 0.1) var shadow_fade_start := 0.8
|
||||
@export var shadow_fade_start := 0.8 # (float, 0.0, 1.0, 0.1)
|
||||
|
||||
# The maximum shadow distance in units. Past this distance, the light will be hidden.
|
||||
export(float, 0.0, 1000.0, 0.1) var light_max_distance := 50
|
||||
@export var light_max_distance := 50 # (float, 0.0, 1000.0, 0.1)
|
||||
|
||||
# The distance factor at which the light starts fading.
|
||||
# A value of 0.0 will result in the smoothest transition whereas a value of 1.0 disables fading.
|
||||
export(float, 0.0, 1.0, 0.1) var light_fade_start := 0.8
|
||||
@export var light_fade_start := 0.8 # (float, 0.0, 1.0, 0.1)
|
||||
|
||||
# The rate at which LODs will be updated (in seconds). Lower values are more reactive
|
||||
# but use more CPU, which is especially noticeable with large amounts of LOD-enabled nodes.
|
||||
@@ -35,7 +36,7 @@ var refresh_rate := 0.05
|
||||
# Positive values will decrease the detail level and improve performance.
|
||||
# Negative values will improve visual appearance at the cost of performance.
|
||||
# This can overridden by setting the project setting `lod/bias`.
|
||||
var lod_bias := 0.0
|
||||
var lod_distance_bias := 0.0
|
||||
|
||||
# The internal refresh timer.
|
||||
var timer := 0.0
|
||||
@@ -46,13 +47,13 @@ var base_light_energy := light_energy
|
||||
|
||||
func _ready() -> void:
|
||||
if ProjectSettings.has_setting("lod/light_bias"):
|
||||
lod_bias = ProjectSettings.get_setting("lod/light_bias")
|
||||
lod_distance_bias = ProjectSettings.get_setting("lod/light_bias")
|
||||
if ProjectSettings.has_setting("lod/light_refresh_rate"):
|
||||
refresh_rate = ProjectSettings.get_setting("lod/light_refresh_rate")
|
||||
|
||||
# Add random jitter to the timer to ensure LODs don't all swap at the same time.
|
||||
randomize()
|
||||
timer += rand_range(0, refresh_rate)
|
||||
timer += randf_range(0, refresh_rate)
|
||||
|
||||
# Despite LOD not being related to physics, we chose to run in `_physics_process()`
|
||||
# to minimize the amount of method calls per second (and therefore decrease CPU usage).
|
||||
@@ -61,7 +62,7 @@ func _physics_process(delta: float) -> void:
|
||||
return
|
||||
|
||||
# We need a camera to do the rest.
|
||||
var camera := get_viewport().get_camera()
|
||||
var camera := get_viewport().get_camera_3d()
|
||||
if camera == null:
|
||||
return
|
||||
|
||||
@@ -71,7 +72,7 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
timer = 0.0
|
||||
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_bias
|
||||
var distance := camera.global_transform.origin.distance_to(global_transform.origin) + lod_distance_bias
|
||||
|
||||
visible = distance < light_max_distance
|
||||
var light_fade_start_distance := light_max_distance * light_fade_start
|
||||
@@ -82,11 +83,3 @@ func _physics_process(delta: float) -> void:
|
||||
light_energy = base_light_energy
|
||||
|
||||
shadow_enabled = distance < shadow_max_distance
|
||||
var shadow_fade_start_distance := shadow_max_distance * shadow_fade_start
|
||||
var shadow_value: float
|
||||
if distance > shadow_fade_start_distance:
|
||||
shadow_value = min(1, (distance - shadow_fade_start_distance) / (shadow_max_distance - shadow_fade_start_distance))
|
||||
else:
|
||||
# We're close enough to the light to show its shadow at full darkness.
|
||||
shadow_value = 0.0
|
||||
shadow_color = Color(shadow_value, shadow_value, shadow_value)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://d3astipm6q338
|
||||
@@ -1,8 +1,9 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/lod_spot_light.svg-22de3bf1089e94662394255ca8159db9.stex"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://qc2optw5cldv"
|
||||
path="res://.godot/imported/lod_spot_light.svg-22de3bf1089e94662394255ca8159db9.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
@@ -10,25 +11,33 @@ metadata={
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/lod/lod_spot_light.svg"
|
||||
dest_files=[ "res://.import/lod_spot_light.svg-22de3bf1089e94662394255ca8159db9.stex" ]
|
||||
dest_files=["res://.godot/imported/lod_spot_light.svg-22de3bf1089e94662394255ca8159db9.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@tool
|
||||
# Copyright © 2020 Hugo Locurcio and contributors - MIT License
|
||||
# See `LICENSE.md` included in the source distribution for details.
|
||||
#
|
||||
# This script is needed to make the `class_name` script visible in the Create New Node dialog
|
||||
# once the plugin is enabled.
|
||||
tool
|
||||
extends EditorPlugin
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://btdo13snbx7nb
|
||||
Vendored
+9
-20
@@ -1,28 +1,17 @@
|
||||
[gd_resource type="Environment" load_steps=3 format=2]
|
||||
[gd_resource type="Environment" format=3 uid="uid://cosbxx1qhfx35"]
|
||||
|
||||
[ext_resource path="res://assets/hdri/tx_night_place.hdr" type="Texture" id=1]
|
||||
|
||||
[sub_resource type="PanoramaSky" id=2]
|
||||
panorama = ExtResource( 1 )
|
||||
[sub_resource type="Sky" id="2"]
|
||||
|
||||
[resource]
|
||||
background_mode = 3
|
||||
background_sky = SubResource( 2 )
|
||||
background_color = Color( 0.188235, 0.133333, 0.133333, 1 )
|
||||
background_energy = 0.6
|
||||
ambient_light_color = Color( 0.694118, 0.168627, 0.67451, 1 )
|
||||
ambient_light_energy = 1.55
|
||||
background_color = Color(0.188235, 0.133333, 0.133333, 1)
|
||||
sky = SubResource("2")
|
||||
ambient_light_color = Color(0.694118, 0.168627, 0.67451, 1)
|
||||
ambient_light_sky_contribution = 0.5
|
||||
ambient_light_energy = 1.55
|
||||
tonemap_mode = 2
|
||||
glow_enabled = true
|
||||
fog_enabled = true
|
||||
fog_color = Color( 0.562167, 0.29, 1, 0.941176 )
|
||||
fog_depth_curve = 1.10957
|
||||
fog_depth_begin = 0.0
|
||||
fog_depth_end = 60.0
|
||||
fog_depth_curve = 1.10957
|
||||
fog_height_enabled = true
|
||||
fog_height_min = 2.0
|
||||
fog_height_max = -20.0
|
||||
fog_height_curve = 0.965936
|
||||
tonemap_mode = 2
|
||||
ss_reflections_enabled = true
|
||||
dof_blur_far_distance = 2.0
|
||||
glow_enabled = true
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://c7ps8q01ej5du"
|
||||
path="res://.godot/imported/MKX Title.ttf-512f7a6aab4653a1f1f61ada9d68c77a.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/fonts/MKX Title.ttf"
|
||||
dest_files=["res://.godot/imported/MKX Title.ttf-512f7a6aab4653a1f1f61ada9d68c77a.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
disable_embedded_bitmaps=true
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
modulate_color_glyphs=false
|
||||
hinting=1
|
||||
subpixel_positioning=4
|
||||
keep_rounding_remainders=true
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
||||
@@ -1,7 +1,6 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
[gd_resource type="FontVariation" format=3 uid="uid://ehvxks08bpr"]
|
||||
|
||||
[ext_resource path="res://assets/fonts/MKX Title.ttf" type="DynamicFontData" id=1]
|
||||
[ext_resource type="FontFile" uid="uid://c7ps8q01ej5du" path="res://assets/fonts/MKX Title.ttf" id="1"]
|
||||
|
||||
[resource]
|
||||
size = 30
|
||||
font_data = ExtResource( 1 )
|
||||
base_font = ExtResource("1")
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://c1wk0en7c3mpr"
|
||||
path="res://.godot/imported/kirsty bd it.otf-bc7aa29ac3e576434d66f4370e7210d1.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/fonts/kirsty/kirsty bd it.otf"
|
||||
dest_files=["res://.godot/imported/kirsty bd it.otf-bc7aa29ac3e576434d66f4370e7210d1.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
disable_embedded_bitmaps=true
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
modulate_color_glyphs=false
|
||||
hinting=1
|
||||
subpixel_positioning=4
|
||||
keep_rounding_remainders=true
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
||||
@@ -0,0 +1,36 @@
|
||||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://bgrwp4g3d0ywx"
|
||||
path="res://.godot/imported/kirsty bd.otf-ca5d4e790ddf12f0b6904680ae840b34.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/fonts/kirsty/kirsty bd.otf"
|
||||
dest_files=["res://.godot/imported/kirsty bd.otf-ca5d4e790ddf12f0b6904680ae840b34.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
disable_embedded_bitmaps=true
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
modulate_color_glyphs=false
|
||||
hinting=1
|
||||
subpixel_positioning=4
|
||||
keep_rounding_remainders=true
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
||||
@@ -0,0 +1,36 @@
|
||||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://dsixnafr172kk"
|
||||
path="res://.godot/imported/kirsty rg it.otf-c12188a557bf88ecddef6b02df5b15ad.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/fonts/kirsty/kirsty rg it.otf"
|
||||
dest_files=["res://.godot/imported/kirsty rg it.otf-c12188a557bf88ecddef6b02df5b15ad.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
disable_embedded_bitmaps=true
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
modulate_color_glyphs=false
|
||||
hinting=1
|
||||
subpixel_positioning=4
|
||||
keep_rounding_remainders=true
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
||||
@@ -0,0 +1,36 @@
|
||||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://c0gq63h6u1c0f"
|
||||
path="res://.godot/imported/kirsty rg.otf-3775cb67524e1b791919a65fd2a6e3a1.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/fonts/kirsty/kirsty rg.otf"
|
||||
dest_files=["res://.godot/imported/kirsty rg.otf-3775cb67524e1b791919a65fd2a6e3a1.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
disable_embedded_bitmaps=true
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
modulate_color_glyphs=false
|
||||
hinting=1
|
||||
subpixel_positioning=4
|
||||
keep_rounding_remainders=true
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
||||
@@ -1,8 +1,6 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
[gd_resource type="FontVariation" format=3 uid="uid://inv1rofq17xy"]
|
||||
|
||||
[ext_resource path="res://assets/fonts/kirsty/kirsty rg.otf" type="DynamicFontData" id=1]
|
||||
[ext_resource type="FontFile" uid="uid://c0gq63h6u1c0f" path="res://assets/fonts/kirsty/kirsty rg.otf" id="1"]
|
||||
|
||||
[resource]
|
||||
use_mipmaps = true
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
||||
base_font = ExtResource("1")
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
[gd_resource type="FontVariation" format=3 uid="uid://dxs8032ya4bwr"]
|
||||
|
||||
[ext_resource path="res://assets/fonts/kirsty/kirsty rg.otf" type="DynamicFontData" id=1]
|
||||
[ext_resource type="FontFile" uid="uid://c0gq63h6u1c0f" path="res://assets/fonts/kirsty/kirsty rg.otf" id="1"]
|
||||
|
||||
[resource]
|
||||
size = 24
|
||||
use_mipmaps = true
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
||||
base_font = ExtResource("1")
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
[gd_resource type="FontVariation" format=3 uid="uid://bqx3uv23bwjul"]
|
||||
|
||||
[ext_resource path="res://assets/fonts/kirsty/kirsty bd.otf" type="DynamicFontData" id=1]
|
||||
[ext_resource type="FontFile" uid="uid://bgrwp4g3d0ywx" path="res://assets/fonts/kirsty/kirsty bd.otf" id="1"]
|
||||
|
||||
[resource]
|
||||
size = 46
|
||||
use_mipmaps = true
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
||||
base_font = ExtResource("1")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user