a
|
@ -161,6 +161,8 @@ I canali di trasferimento attualmente disponibili sono:
|
|||
- `unreliable_ordered`, che aggiunge un contatore ad ogni pacchetto inviato tramite UDP, facendo in modo che i peer possano ignorare i pacchetti arrivati nell'ordine sbagliato;
|
||||
- `reliable`, che implementa un protocollo di acknowledgement su UDP molto simile a quello utilizzato da TCP, a costo di una latenza significativamente maggiore.
|
||||
|
||||
> Dove non specificato, in questa relazione si assume che una RPC descritta usi sempre il canale `reliable`.
|
||||
|
||||
## Nodi di sincronizzazione
|
||||
|
||||
Godot mette a disposizione dei `Node` speciali per assistere con la sincronizzazione dello stato del gioco tra tutti i peer.
|
||||
|
|
|
@ -16,7 +16,7 @@ Il `Node` `Main` è alla radice di ogni istanza del gioco, e si occupa di inizi
|
|||
|
||||
## [`Game`](../scenes/game.gd)
|
||||
|
||||
Il `Node` `Game` viene collocato sempre come figlio di `Main`, e rappresenta lo stato di gioco di un peer, che esso sia un server o un client.
|
||||
Il `Node` `Game` viene collocato sempre come figlio di `Main`, e rappresenta lo stato di gioco di un peer connesso ad una specifica stanza (anche detta "lobby" in inglese), che esso sia un server o un client.
|
||||
|
||||
Il server ha sempre autorità su di esso, e:
|
||||
|
||||
|
@ -26,24 +26,136 @@ Il server ha sempre autorità su di esso, e:
|
|||
- quando il giocatore host richiede attraverso l'interfaccia grafica di iniziare la partita, usa il `PhaseTracker` per cambiare ovunque la fase della partita da `LOBBY` a `PLAYING`, e richiede al `LevelManager` di istanziare il primo livello;
|
||||
- quando il `LevelManager` segnala che la `LevelPlaylist` selezionata è esaurita, usa il `PhaseTracker` per aggiornare la fase della partita da `PLAYING` a `ENDED`.
|
||||
|
||||
![](img/game.png)
|
||||
|
||||
## [`PeerNodeDirectory`](../scenes/peernode_directory.gd)
|
||||
|
||||
Il `Node` `PeerNodeDirectory`, essendo contenuto nella scena `game.tscn`, viene istanziato ricorsivamente in tutte le istanze di `Game`.
|
||||
|
||||
Come menzionato in precedenza, ha la responsabilità di mantenere aggiornato l'indice dei peer connessi, e a tale scopo rende disponibili al server le remote procedure call `rpc_create_peernode(peer_id)` e `rpc_destroy_peernode(peer_id)` in modo da permettere al server (e solo al server) di informare tutti i client dello stato attuale dei client connessi.
|
||||
|
||||
![](img/peernodedirectory.png)
|
||||
|
||||
## [`PeerNode`](../scenes/peernode.gd)
|
||||
|
||||
Il `Node` `PeerNode` rappresenta un singolo peer connesso, di cui ne è la `multiplayer_authority`, e ha il suo identificatore impostato come proprietà `name`.
|
||||
|
||||
Ha un singolo metodo, che può essere chiamato come RPC solamente dal peer che controlla il nodo stesso: `rpc_identify`, che comunica al server il nome con cui il peer appena connesso si identifica agli altri.
|
||||
|
||||
Quando il server riceve un'identificazione di un peer, il relativo `PeerNode` emette il segnale `identified`, che viene propagato in alto fino a `Game`, il quale lo gestisce come descritto sopra.
|
||||
|
||||
## [`PlayerNodeDirectory`](../scenes/playernode_directory.gd)
|
||||
|
||||
Il `Node` `PlayerNodeDirectory` è molto simile a `PeerNodeDirectory`, ma invece che dei peer, tiene traccia dei giocatori effettivi nella partita, indicizzati per nome del giocatore rappresentato.
|
||||
|
||||
Dato che un giocatore, una volta entrato in una lobby, deve mantenere il proprio punteggio fino a quando la partita non è terminata, anche se non l'ha terminata perchè l'ha abbandonata a metà, non è incluso un modo per rimuovere un giocatore dall'indice, ma soltanto uno per aggiungerne uno nuovo.
|
||||
|
||||
Questo metodo è `rpc_possess_playernode(player_name, peer_id)`, chiamabile solo dal server, che controlla se un giocatore con il dato nome è già indicizzato, creando il relativo `PlayerNode` in caso negativo, e in entrambi i casi (ri)assegnando l'autorità su di esso al peer con l'identificatore specificato.
|
||||
|
||||
In aggiunta, è disponibile `rpc_push_reported_scores()`, chiamabile anch'essa solo dal server, che fa in modo che tutti i `PlayerNode` figli spostino in una lista il numero di colpi impiegati per entrare nella buca attuale (`reported_score`, descritto in seguito), resettando poi il contatore in preparazione alla buca successiva.
|
||||
|
||||
![](img/playernodedirectory.png)
|
||||
|
||||
## [`PlayerNode`](../scenes/playernode.gd)
|
||||
|
||||
Il `Node` `PlayerNode` rappresenta un singolo giocatore nella partita, e la sua `multiplayer_authority` può variare in base ai peer attualmente connessi alla partita: essa prende il valore dell'ultimo peer che si è identificato con il relativo nome, se esso è ancora connesso, altrimenti l'autorità è assegnata al server fino a quando un nuovo peer non si riconnetterà con quel nome.
|
||||
|
||||
Esso include tante proprietà e metodi, in quanto è ciò che permette ai dati di uno specifico giocatore di persistere tra un livello e l'altro.
|
||||
|
||||
Tra questi, sono degni di nota:
|
||||
- `sanitize_player_name`, una funzione statica che sostituisce con un underscore (`_`) tutti i caratteri non validi all'interno per il nome di un nodo (`/`, `*`, ` `) dal nome del giocatore;
|
||||
- `player_name`, proprietà che assieme al nome del nodo stesso riflette il nome del giocatore (necessaria per via di un dettaglio implementativo di come Godot gestisce le stringhe nei nomi);
|
||||
- `rpc_set_name`, remote procedure call chiamabile solo dall'autorità che modifica il nome del giocatore in questione
|
||||
- il segnale `name_changed`, emesso quando il nome viene cambiato;
|
||||
- `rpc_query_name`, remote procedure call chiamabile da qualsiasi peer che richiede all'autorità di ripetere `rpc_set_name` con il nome attuale, in modo da comunicarlo anche ad un peer che si è connesso successivamente alla prima chiamata;
|
||||
- `player_color`, proprietà che rappresenta il colore del giocatore;
|
||||
- `rpc_set_color`, authority RPC che modifica il colore;
|
||||
- il segnale `color_changed`, emesso quando il colore viene cambiato;
|
||||
- `rpc_query_color`, che fa ripetere `rpc_set_color` all'autorità con il colore attuale;
|
||||
- `possess`, funzione di utilità che modifica la `multiplayer_authority` del nodo al valore dato;
|
||||
- il segnale `possessed`, emesso quando la `multiplayer_authority` è modificata attraverso `possess`;
|
||||
- `hole_scores`, lista di `int` che rappresentano i colpi richiesti dal giocatore per entrare in buca nelle buche precedenti;
|
||||
- `rpc_set_scores`, remote procedure call chiamabile solo dall'autorità che modifica la lista dei punteggi;
|
||||
- `rpc_query_scores`, che fa ripetere `rpc_set_scores` all'autorità con i punteggi attuali;
|
||||
- il segnale `scores_changed`, emesso quando i punteggi vengono cambiati;
|
||||
- `reported_score`, proprietà che assume il valore di `-1` mentre il giocatore sta affrontando la buca, e ottiene un valore corrispondente al numero di colpi impiegati per terminarla una volta finita;
|
||||
- `rpc_report_score`, remote procedure call chiamabile solo dall'autorità che imposta un reported score;
|
||||
- il segnale `score_reported`, emesso quando viene impostato un `reported_score` tramite `rpc_report_score`.
|
||||
|
||||
## [`PhaseTracker`](../scenes/phase_tracker.gd)
|
||||
|
||||
Il `Node` `PhaseTracker` si occupa di tenere traccia della fase in cui si trova la partita in ogni dato momento.
|
||||
|
||||
Le fasi possibili, rappresentate dall'enumerazione `Phase` e immagazzinate nella proprietà `phase`, sono:
|
||||
- `LOBBY`, il momento pre-partita in cui viene visualizzato l'elenco dei giocatori connessi ed è data all'host la possibilità di iniziare;
|
||||
- `PLAYING`, il momento in cui la partita sta venendo disputata;
|
||||
- `ENDED`, il momento in cui la partita è terminata, e stanno venendo mostrati a schermo i risultati.
|
||||
|
||||
La sua autorità è sempre posseduta dal server, e come `PlayerNode`, include una coppia di RPC per modificare la fase attuale, `rpc_set_phase` e `rpc_query_phase`, più un segnale `phase_changed` emesso quando la fase viene effettivamente cambiata.
|
||||
|
||||
![](img/phasetracker.png)
|
||||
|
||||
## [`LevelPlaylist`](../scenes/level_playlist.gd)
|
||||
|
||||
Il `Node` `LevelPlaylist` contiene una lista `levels`, che in riferimenti a scene rappresentanti i livelli precostruiti che il server invierà ai client.
|
||||
|
||||
L'indice del livello attuale viene salvato nella proprietà `idx`, mentre una funzione `advance` restituisce il prossimo livello dalla lista emettendo simultaneamente il segnale `advanced(level)`.
|
||||
|
||||
Sui client, `idx` rimane sempre fisso a `-1`, in quanto essi non caricano il livello da una lista predefinita, ma lo costruiscono dinamicamente in base ai dati che il server invia loro.
|
||||
|
||||
![](img/levelplaylist.png)
|
||||
|
||||
## [`LevelManager`](../scenes/level_manager.gd)
|
||||
|
||||
Il `Node` `LevelManager` è gestito dal server, e si occupa di inizializzare i livelli sia su client, sia su server.
|
||||
|
||||
Fa uso di tre RPC chiamabili solo dal server:
|
||||
- `rpc_wipe_level`, che decostruisce il livello attuale, se presente, e ne inizializza uno nuovo, preso dalla `LevelPlaylist`;
|
||||
- `rpc_destroy_level`, che distrugge il livello attuale e non fa nient'altro, usato per procedere in sicurezza alla schermata dei risultati;
|
||||
- `rpc_level_completed`, che emette il segnale `level_completed` su tutti i client.
|
||||
|
||||
Sono inclusi numerosi segnali che corrispondono alle varie fasi del ciclo di vita di un livello, come `level_destroying`, `level_destroyed`, `level_determined`, `level_initialized`, `level_built` e `level_completed`.
|
||||
|
||||
Un segnale specifico è relativo al ciclo di vita dell'intera playlist: quando i livelli disponibili sono esauriti, viene emesso il segnale `playlist_complete`, che viene poi raccolto da `Game` per avanzare alla fase `ENDED`.
|
||||
|
||||
![](img/levelmanager.png)
|
||||
|
||||
## [`GolfLevel`](../scenes/golf_level.gd)
|
||||
|
||||
Il **`Node2D`** `GolfLevel` è ancora una volta gestito dal server, e contiene gli elementi "effettivi" della buca che i giocatori andranno ad affrontare.
|
||||
|
||||
Si può comportare in due diversi modi in base al contesto in cui viene usato:
|
||||
- gli può essere specificata nella proprietà `target` una scena contenente un altro `GolfLevel` da `LevelManager`; essa verrà istanziata senza essere aggiunta al mondo di gioco, poi da quella scena verranno lette varie proprietà dai nodi `FollowCamera`, `GolfTee`, `GolfHole` e `TileMap` presenti in essa e attraverso RPC saranno replicate su tutti i peer;
|
||||
- gli può essere specificato `null` nella proprietà `target`, rimanendo così in attesa di ricevere RPC dal server per costruire il livello secondo istruzioni.
|
||||
|
||||
![](img/golflevel.png)
|
||||
|
||||
### Replicazione remota di `GolfLevel`
|
||||
|
||||
La replicazione remota di un livello segue i seguenti passi:
|
||||
|
||||
1. il server legge la `global_position`, `global_rotation` e `global_scale` della `TileMap` target, poi chiama `rpc_build_tilemap` usandoli come argomenti, istanziando nel mondo di gioco una griglia vuota nella stessa configurazione di quella target;
|
||||
2. il server itera su tutti i tile della `TileMap` target, e per ciascuno chiama `rpc_build_tilemap_cell` passandogli le caratteristiche del tile da copiare, istanziando così nel mondo di gioco i "muretti" della buca;
|
||||
3. il server guarda la posizione del `GolfTee` target, e usa `rpc_build_tee` per ricrearlo lì, connettendo inoltre il suo segnale `everyone_entered_hole` a una sua funzione interna che fa arrivare `level_completed` a `LevelManager` dopo qualche secondo;
|
||||
4. il server itera su tutti i `PlayerNode` presenti nella `PlayerNodeDirectory` del `Game` attuale, e per ognuno di essi chiama `rpc_build_ball` con le relative caratteristiche, che includono la posizione, il numero attuale di colpi effettuati, e se la pallina è entrata in buca;
|
||||
5. il server guarda la posizione e la dimensione della `GolfHole` target, e chiama `rpc_build_hole` passandoglieli come parametri,
|
||||
6. il server guarda la posizione di `FollowCamera`, e controlla il parametro `camera_follows_payer` del target, per poi istanziare una nuova `FollowCamera` nel mondo di gioco e, se `camera_follows_player` è attivato, la configura per seguire la `GolfBall` controllata dal giocatore locale.
|
||||
|
||||
## [`GolfTee`](../scenes/golf_tee.gd)
|
||||
|
||||
Il `Node2D` `GolfTee` è sempre gestito dal server, e funziona sia da directory delle "palline" che i giocatori controllano nel corso del livello, sia come loro istanziatore.
|
||||
|
||||
Non contiene remote procedure call, perchè la `GolfLevel` ha la responsabilità di richiedere ai peer la creazione di una nuova entità del livello, ma contiene un metodo `spawn` di cui `rpc_build_ball` fa uso.
|
||||
|
||||
Connette i segnali `name_changed`, `color_changed`, `possessed` emessi dal `PlayerNode` alle `GolfBall` `spawn`ate per rimanere sincronizzata con lo stato della stanza: ad esempio, se il giocatore dovesse disconnettersi, la relativa `GolfBall` verrebbe nascosta dal mondo di gioco, ma comunque mantenuta, in modo che qualora il giocatore si riconnetterà, continuerà a disputare la buca dalla posizione in cui si è disconnesso.
|
||||
|
||||
Inoltre, ogni volta che una `GolfBall` da esso istanziata entra nella buca, `GolfTee` chiama `rpc_report_score` sul relativo `PlayerNode`, e poi controlla se tutte le palline dei giocatori connessi (e quindi la cui `multiplayer_authority` del relativo `PlayerNode` è diversa da quella del server) sono entrate in buca, emettendo esso stesso il segnale `everyone_entered_hole`, che `GolfLevel` usa per determinare quando avanzare di livello.
|
||||
|
||||
![](img/golftee.png)
|
||||
|
||||
## [`GolfBall`](../scenes/golf_ball.gd)
|
||||
|
||||
|
||||
|
||||
|
||||
## [`PuttController`](../scenes/putt_controller.gd)
|
||||
|
|
BIN
docs/img/game.png
Normal file
After Width: | Height: | Size: 971 KiB |
34
docs/img/game.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://by4gofram0cbi"
|
||||
path="res://.godot/imported/game.png-fcdac8ac86fa7d0c58685bcddac3a78a.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/img/game.png"
|
||||
dest_files=["res://.godot/imported/game.png-fcdac8ac86fa7d0c58685bcddac3a78a.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
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
|
BIN
docs/img/golflevel.png
Normal file
After Width: | Height: | Size: 237 KiB |
34
docs/img/golflevel.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dvuju4q6alwyp"
|
||||
path="res://.godot/imported/golflevel.png-d27e4983f59b7723a043af42b28f8be5.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/img/golflevel.png"
|
||||
dest_files=["res://.godot/imported/golflevel.png-d27e4983f59b7723a043af42b28f8be5.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
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
|
BIN
docs/img/golftee.png
Normal file
After Width: | Height: | Size: 124 KiB |
34
docs/img/golftee.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://chxkkxrdxhdy3"
|
||||
path="res://.godot/imported/golftee.png-252e0b2f30e9a9c0c38ea9fb7be1663b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/img/golftee.png"
|
||||
dest_files=["res://.godot/imported/golftee.png-252e0b2f30e9a9c0c38ea9fb7be1663b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
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
|
BIN
docs/img/levelmanager.png
Normal file
After Width: | Height: | Size: 87 KiB |
34
docs/img/levelmanager.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cpx3bq8v74ms0"
|
||||
path="res://.godot/imported/levelmanager.png-1d5d66e9ab6d9122e97efa1bce2c6829.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/img/levelmanager.png"
|
||||
dest_files=["res://.godot/imported/levelmanager.png-1d5d66e9ab6d9122e97efa1bce2c6829.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
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
|
BIN
docs/img/levelplaylist.png
Normal file
After Width: | Height: | Size: 200 KiB |
34
docs/img/levelplaylist.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cexns0yby3b03"
|
||||
path="res://.godot/imported/levelplaylist.png-81c22442bdcead8e3a74dd48b9e2cf77.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/img/levelplaylist.png"
|
||||
dest_files=["res://.godot/imported/levelplaylist.png-81c22442bdcead8e3a74dd48b9e2cf77.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
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
|
BIN
docs/img/peernodedirectory.png
Normal file
After Width: | Height: | Size: 194 KiB |
34
docs/img/peernodedirectory.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bp8dcwk8spldq"
|
||||
path="res://.godot/imported/peernodedirectory.png-919e1251618461314bba777535202563.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/img/peernodedirectory.png"
|
||||
dest_files=["res://.godot/imported/peernodedirectory.png-919e1251618461314bba777535202563.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
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
|
BIN
docs/img/phasetracker.png
Normal file
After Width: | Height: | Size: 70 KiB |
34
docs/img/phasetracker.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b0b237n4m3se1"
|
||||
path="res://.godot/imported/phasetracker.png-008c365a66e2dc23bda5107f3070a7b6.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/img/phasetracker.png"
|
||||
dest_files=["res://.godot/imported/phasetracker.png-008c365a66e2dc23bda5107f3070a7b6.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
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
|
BIN
docs/img/playernodedirectory.png
Normal file
After Width: | Height: | Size: 193 KiB |
34
docs/img/playernodedirectory.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b63iya8v3xypu"
|
||||
path="res://.godot/imported/playernodedirectory.png-e5070e4b69e8c7c8f32804b2b8f671ab.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/img/playernodedirectory.png"
|
||||
dest_files=["res://.godot/imported/playernodedirectory.png-e5070e4b69e8c7c8f32804b2b8f671ab.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
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
|