Skip to content

Commit

Permalink
Clean godot-xr-tools to have no warnings against gdlint (https://gith…
Browse files Browse the repository at this point in the history
…ub.com/Scony/godot-gdscript-toolkit)  version 3.4.0 (#310)

Added github workflow to run gdlint.

Fix runs-on declaration for action

Added python-version specification to remove action warning.
  • Loading branch information
Malcolmnixon authored Dec 29, 2022
1 parent b95c610 commit b2d0d30
Show file tree
Hide file tree
Showing 28 changed files with 697 additions and 426 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/gdlint-on-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Workflow to automatically lint gdscript code
name: gdlint on push

on:
[push, pull_request]

jobs:
gdlint:
name: gdlint scripts
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'gdtoolkit==3.*'
- name: Lint Godot XR Tools
run: |
gdlint addons/godot-xr-tools
301 changes: 178 additions & 123 deletions addons/godot-xr-tools/assets/resource_queue/resource_queue.gd
Original file line number Diff line number Diff line change
@@ -1,166 +1,221 @@
class_name XRToolsResourceQueue
extends Node

var thread
var mutex
var semaphore
var exit_thread = false

var time_max = 100 # Milliseconds.
## XRTools Threaded Resource Loader
##
## This class can be used to perform resource loading in the background without
## interrupting the application.

var queue = []
var pending = {}

func _lock(_caller):
mutex.lock()
# Thread to perform the loading
var _thread : Thread

# Mutex for safe synchronization
var _mutex : Mutex

func _unlock(_caller):
mutex.unlock()
# Semaphore to wake up the loader thread
var _semaphore : Semaphore

# Thread exit flag
var _exit_thread : bool = false

func _post(_caller):
semaphore.post()
# Queue of ResourceInteractiveLoader instances loading resources
var _queue = []

# Dictionary of pending results by resource path.
#
# If the resource is still loading then the value is a ResourceInteractiveLoader.
# If the resource has loaded then the value is a Resource.
var _pending = {}

func _wait(_caller):
semaphore.wait()

## Queue the loading of a resource
func queue_resource(path : String, p_in_front : bool = false) -> void:
# Lock the synchronization mutex
_mutex.lock()

func queue_resource(path, p_in_front = false):
_lock("queue_resource")
if path in pending:
_unlock("queue_resource")
# Test if the resource has already been queued
if path in _pending:
# Work already queued, nothing to do.
_mutex.unlock()
return
elif ResourceLoader.has_cached(path):
var res = ResourceLoader.load(path)
pending[path] = res
_unlock("queue_resource")

# Test if the ResourceLoader already has it cached
if ResourceLoader.has_cached(path):
# Put the resource in the pending-results dictionary
_pending[path] = ResourceLoader.load(path)
_mutex.unlock()
return

# Construct a ResourceInteractiveLoader for the resource
var loader = ResourceLoader.load_interactive(path)

# Save the resource path in the metadata for later use
loader.set_meta("path", path)

# Insert into the loading-queue (front for high priority)
if p_in_front:
_queue.push_front(loader)
else:
var res = ResourceLoader.load_interactive(path)
res.set_meta("path", path)
if p_in_front:
queue.insert(0, res)
else:
queue.push_back(res)
pending[path] = res
_post("queue_resource")
_unlock("queue_resource")
return
_queue.push_back(loader)

# Save the loader in the pending-results dictionary
_pending[path] = loader

func cancel_resource(path):
_lock("cancel_resource")
if path in pending:
if pending[path] is ResourceInteractiveLoader:
queue.erase(pending[path])
pending.erase(path)
_unlock("cancel_resource")
# Post the semaphore to wake the worker thread
_mutex.unlock()
_semaphore.post()


func get_progress(path):
_lock("get_progress")
var ret = -1
if path in pending:
if pending[path] is ResourceInteractiveLoader:
ret = float(pending[path].get_stage()) / float(pending[path].get_stage_count())
else:
ret = 1.0
_unlock("get_progress")
return ret
## Cancel loading a resource
func cancel_resource(path : String) -> void:
# Lock the synchronization mutex
_mutex.lock()

# Inspect the pending-results dictionary
if path in _pending:
# Extract the item from the pending-results dictionary
var item = _pending[path]
_pending.erase(path)

func is_ready(path):
var ret
_lock("is_ready")
if path in pending:
ret = !(pending[path] is ResourceInteractiveLoader)
else:
ret = false
_unlock("is_ready")
return ret
# If the item is still being loaded then remove it from the loading-queue
if item is ResourceInteractiveLoader:
_queue.erase(item)

# Loading cancelled
_mutex.unlock()

func _wait_for_resource(res, path):
_unlock("wait_for_resource")
while true:
VisualServer.sync()
OS.delay_usec(16000) # Wait approximately 1 frame.
_lock("wait_for_resource")
if queue.size() == 0 || queue[0] != res:
return pending[path]
_unlock("wait_for_resource")


func get_resource(path):
_lock("get_resource")
if path in pending:
if pending[path] is ResourceInteractiveLoader:
var res = pending[path]
if res != queue[0]:
var pos = queue.find(res)
queue.remove(pos)
queue.insert(0, res)

res = _wait_for_resource(res, path)
pending.erase(path)
_unlock("return")
return res

## Get the progress of a loading resource
func get_progress(path : String) -> float:
# Lock the synchronization mutex
_mutex.lock()

# Inspect the pending results dictionary for the progress
var progress := -1.0
if path in _pending:
var item = _pending[path]
if item is ResourceInteractiveLoader:
# The item is still loading, calculate the progress
progress = float(item.get_stage()) / float(item.get_stage_count())
else:
var res = pending[path]
pending.erase(path)
_unlock("return")
return res
else:
_unlock("return")
return ResourceLoader.load(path)
# The item is fully loaded
progress = 1.0

# Return the progress
_mutex.unlock()
return progress


func thread_process():
_wait("thread_process")
_lock("process")
## Test if a resouece is ready
func is_ready(path : String) -> bool:
# Lock the synchronization mutex
_mutex.lock()

while queue.size() > 0:
var res = queue[0]
_unlock("process_poll")
var ret = res.poll()
_lock("process_check_queue")
# Inspect the pending results dictionary for the ready status
var ready := false
if path in _pending:
var item = _pending[path]
ready = not item is ResourceInteractiveLoader

if ret == ERR_FILE_EOF || ret != OK:
var path = res.get_meta("path")
if path in pending: # Else, it was already retrieved.
pending[res.get_meta("path")] = res.get_resource()
# Something might have been put at the front of the queue while
# we polled, so use erase instead of remove.
queue.erase(res)
_unlock("process")
# Return the ready status
_mutex.unlock()
return ready


func thread_func(_u):
## Get the resource
func get_resource(path : String) -> Resource:
# Lock the synchronization mutex
_mutex.lock()

# Test if the resource is unknown
if not path in _pending:
# Not queued, just load immediately
_mutex.unlock()
return ResourceLoader.load(path)

# Loop waiting for resource to load
var res
while true:
mutex.lock()
var should_exit = exit_thread # Protect with Mutex.
mutex.unlock()
# Get the item from the pending-results dictionary
res = _pending[path]

if should_exit:
# Detect loading complete
if res == null or res is Resource:
break
thread_process()

# Give thread more time to load the item
_mutex.unlock()
OS.delay_usec(16000) # Wait approximately 1 frame.
_mutex.lock();

_pending.erase(path)
_mutex.unlock()
return res


## Start the resource queue
func start():
mutex = Mutex.new()
semaphore = Semaphore.new()
thread = Thread.new()
thread.start(self, "thread_func", 0)
_mutex = Mutex.new()
_semaphore = Semaphore.new()
_thread = Thread.new()
_thread.start(self, "_thread_func", 0)


# Triggered by calling "get_tree().quit()".
func _exit_tree():
mutex.lock()
exit_thread = true # Protect with Mutex.
mutex.unlock()
_mutex.lock()
_exit_thread = true # Protect with Mutex.
_mutex.unlock()

# Unblock by posting.
semaphore.post()
# Wake the worker thread
_semaphore.post()

# Wait until it exits.
thread.wait_to_finish()
_thread.wait_to_finish()


# Thread worker function
func _thread_func(_u):
# Lock the synchronization mutex
_mutex.lock()

# Loop processing work
while true:
# Handle a request to terminate
if _exit_thread:
_mutex.unlock()
return

# Handle no work
if _queue.size() == 0:
# Wait for work (with the mutex unlocked so work can be added)
_mutex.unlock()
_semaphore.wait()
_mutex.lock()
continue

# Get the loader
var loader : ResourceInteractiveLoader = _queue.front()

# Poll the loader (with the mutex unlocked)
_mutex.unlock()
var err = loader.poll()
_mutex.lock()

# If loader is still busy then continue
if err == OK:
continue

# Remove from the loading-queue. Note that something may have been
# put at the front of the queue while we polled, so use erase instead
# of remove
_queue.erase(loader)

# Get the resource path from the loaders metadata
var path : String = loader.get_meta("path")

# If the result is still pending then update it with the resource
if path in _pending:
_pending[path] = loader.get_resource()
9 changes: 6 additions & 3 deletions addons/godot-xr-tools/effects/vignette.gd
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,15 @@ func _process(delta):
# Calculate what our radius should be for our rotation speed
var target_radius = 1.0
if auto_rotation_limit > 0:
target_radius = 1.0 - (clamp(angle / auto_rotation_limit_rad, 0.0, 1.0) * (1.0 - auto_inner_radius))
target_radius = 1.0 - (
clamp(angle / auto_rotation_limit_rad, 0.0, 1.0) * (1.0 - auto_inner_radius))

# Now do the same for speed, this includes players physical speed but there isn't much we can do there.
# Now do the same for speed, this includes players physical speed but there
# isn't much we can do there.
if auto_velocity_limit > 0:
var velocity = delta_v.length() / delta
target_radius = min(target_radius, 1.0 - (clamp(velocity / auto_velocity_limit, 0.0, 1.0) * (1.0 - auto_inner_radius)))
target_radius = min(target_radius, 1.0 - (
clamp(velocity / auto_velocity_limit, 0.0, 1.0) * (1.0 - auto_inner_radius)))

# if our radius is small then our current we apply it
if target_radius < radius:
Expand Down
Loading

0 comments on commit b2d0d30

Please sign in to comment.