Merge branch 'master' into tab_key

This commit is contained in:
Nils ANDRÉ-CHANG 2019-09-12 21:28:49 +01:00
commit 0024dd7bb5
1139 changed files with 102964 additions and 41115 deletions

3
.github/CODEOWNERS vendored
View file

@ -30,7 +30,6 @@ doc_classes/* @godotengine/documentation
/modules/bullet/ @AndreaCatania
/modules/csg/ @BastiaanOlij
/modules/enet/ @godotengine/network
/modules/gdnative/ @karroffel
/modules/gdnative/*arvr/ @BastiaanOlij
/modules/gdscript/ @vnen @bojidar-bg
/modules/mbedtls/ @godotengine/network
@ -45,6 +44,6 @@ doc_classes/* @godotengine/documentation
/platform/uwp/ @vnen
/server/physics*/ @reduz @AndreaCatania
/server/visual*/ @reduz @karroffel
/server/visual*/ @reduz
/thirdparty/ @akien-mga

View file

@ -1,21 +0,0 @@
<!-- Please search existing issues for potential duplicates before filing yours:
https://github.com/godotengine/godot/issues?q=is%3Aissue
-->
**Godot version:**
<!-- Specify commit hash if non-official. -->
**OS/device including version:**
<!-- Specify GPU model and drivers if graphics-related. -->
**Issue description:**
<!-- What happened, and what was expected. -->
**Steps to reproduce:**
**Minimal reproduction project:**
<!-- Recommended as it greatly speeds up debugging. Drag and drop a zip archive to upload it. -->

18
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,18 @@
---
name: Bug report
about: Report a bug in Godot
title: ''
labels: ''
assignees: ''
---
**Godot version:**
**OS/device including version:**
**Issue description:**
**Steps to reproduce:**
**Minimal reproduction project:**

View file

@ -0,0 +1,19 @@
---
name: Feature / Enhancement Request
about: Adding new features or improving existing ones.
title: 'IMPORTANT: This repository no longer accepts feature / enhancement requests.'
labels: ''
assignees: ''
---
**IMPORTANT, PLEASE READ**
Feature / Enhancement requests are no longer accepted in the main Godot repository.
Please open an item by filling the relevant fields in the *Proposals* repository:
https://github.com/godotengine/godot-proposals/issues/new/choose
Do not submit to this repository or your issue will be closed.
**IMPORTANT, PLEASE READ**

1
.gitignore vendored
View file

@ -1,5 +1,6 @@
# Godot auto generated files
*.gen.*
.import/
# Documentation generated by doxygen or from classes.xml
doc/_build/

View file

@ -2,7 +2,10 @@ language: cpp
# OS config, depends on actual 'os' in build matrix
dist: xenial
sudo: false
stages:
- check
- build
env:
global:
@ -18,6 +21,7 @@ cache:
matrix:
include:
- name: Static checks (clang-format)
stage: check
env: STATIC_CHECKS=yes
os: linux
compiler: gcc
@ -29,6 +33,7 @@ matrix:
- clang-format-8
- name: Linux editor (debug, GCC 9, with Mono)
stage: build
env: PLATFORM=x11 TOOLS=yes TARGET=debug CACHE_NAME=${PLATFORM}-tools-mono-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="module_mono_enabled=yes mono_glue=no warnings=extra werror=yes"
os: linux
compiler: gcc-9
@ -52,6 +57,7 @@ matrix:
branch_pattern: coverity_scan
- name: Linux export template (release, Clang)
stage: build
env: PLATFORM=x11 TOOLS=no TARGET=release CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes"
os: linux
compiler: clang
@ -61,22 +67,26 @@ matrix:
- *linux_deps
- name: Android export template (release_debug, Clang)
stage: build
env: PLATFORM=android TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes"
os: linux
compiler: clang
- name: macOS editor (debug, Clang)
stage: build
env: PLATFORM=osx TOOLS=yes TARGET=debug CACHE_NAME=${PLATFORM}-tools-clang
os: osx
compiler: clang
- name: iOS export template (debug, Clang)
stage: build
env: PLATFORM=iphone TOOLS=no TARGET=debug CACHE_NAME=${PLATFORM}-clang
os: osx
compiler: clang
- name: Linux headless editor (release_debug, GCC 9)
env: PLATFORM=server TOOLS=yes TARGET=release_debug CACHE_NAME=${PLATFORM}-tools-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="warnings=extra werror=yes"
- name: Linux headless editor (release_debug, GCC 9, testing project exporting and script running)
stage: build
env: PLATFORM=server TOOLS=yes TARGET=release_debug CACHE_NAME=${PLATFORM}-tools-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="warnings=extra werror=yes" TEST_PROJECT=yes
os: linux
compiler: gcc-9
addons:
@ -88,6 +98,7 @@ matrix:
- *linux_deps
- name: Linux export template (release_debug, GCC 5, without 3D support)
stage: build
env: PLATFORM=x11 TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-gcc-5 EXTRA_ARGS="disable_3d=yes"
os: linux
compiler: gcc
@ -124,5 +135,10 @@ script:
- if [ "$STATIC_CHECKS" = "yes" ]; then
sh ./misc/travis/clang-format.sh;
else
scons -j2 CC=$CC CXX=$CXX platform=$PLATFORM tools=$TOOLS target=$TARGET $OPTIONS $EXTRA_ARGS;
scons -j2 CC=$CC CXX=$CXX platform=$PLATFORM tools=$TOOLS target=$TARGET $OPTIONS $EXTRA_ARGS &&
if [ "$TEST_PROJECT" = "yes" ]; then
git clone --depth 1 "https://github.com/godotengine/godot-tests.git";
sed -i "s:custom_template/release=\"\":custom_template/release=\"$(readlink -e bin/godot_server.x11.opt.tools.64)\":" godot-tests/tests/project_export/export_presets.cfg;
godot-tests/tests/project_export/test_project.sh "bin/godot_server.x11.opt.tools.64";
fi
fi

View file

@ -36,6 +36,7 @@ name is available.
Andy Moss (MillionOstrich)
Anish Bhobe (KidRigger)
Anton Yabchinskiy (a12n)
Anutrix
Aren Villanueva (kurikaesu)
Ariel Manzur (punto-)
Bastiaan Olij (BastiaanOlij)
@ -56,6 +57,7 @@ name is available.
Dharkael (lupoDharkael)
Dmitry Koteroff (Krakean)
DualMatrix
Emmanuel Barroga (sparkart)
Emmanuel Leblond (touilleMan)
Eric Lasota (elasota)
est31
@ -68,6 +70,7 @@ name is available.
Gerrit Großkopf (Grosskopf)
Gilles Roudiere (groud)
Guilherme Felipe de C. G. da Silva (guilhermefelipecgs)
Hanif A (hbina)
Hein-Pieter van Braam (hpvb)
Hiroshi Ogawa (hi-ogawa)
homer666
@ -104,6 +107,7 @@ name is available.
Masoud BH (masoudbh3)
Matthias Hölzl (hoelzl)
Max Hilbrunner (mhilbrunner)
merumelu
Michael Alexsander Silva Dias (YeldhamDev)
mrezai
Nathan Warden (NathanWarden)
@ -128,6 +132,7 @@ name is available.
romulox-x
Ruslan Mustakov (endragor)
Saniko (sanikoyes)
santouits
SaracenOne
sersoong
Simon Wenner (swenner)

153
DONORS.md
View file

@ -17,11 +17,12 @@ generous deed immortalized in the next stable release of Godot Engine.
## Gold sponsors
Gamblify <https://www.gamblify.com>
Moonwards <https://www.moonwards.com>
## Mini sponsors
AD Ford
Alan Beauchamp
Aleksandar Kordic
Anandarup Mallik
Andrew Dunai
Brandon Lamb
@ -30,12 +31,16 @@ generous deed immortalized in the next stable release of Godot Engine.
Christoph Woinke
Denis Malyavin
Edward Flick
Gamechuck
GameDev.net
GameDev.tv
Grady
Hein-Pieter van Braam
Jacob McKenney
Javary Co.
Jeppe Zapp
Justin Arnold
Justo Delgado Baudí
Kyle Szklenski
Leonard Meagher
Matthieu Huvé
@ -46,7 +51,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Patrick Aarstad
Slobodan Milnovic
Stephan Lanfermann
Stephen Telford
Steve
VilliHaukka
Xananax
@ -56,10 +60,11 @@ generous deed immortalized in the next stable release of Godot Engine.
Andrei
cheese65536
Daniel Hartmann
Dave
David Gehrig
Ed Morley
Florian Krick
Grady
Jakub Grzesik
K9Kraken
Manuele Finocchiaro
@ -70,56 +75,62 @@ generous deed immortalized in the next stable release of Godot Engine.
Zaven Muradyan
Alexander Trey Saunders
Allen Schade
Asher Glick
Austen McRae
beVR
Brian van der Stel
Cameron MacNair
Carlo Cabanilla
Daniel James
David Giardi
David Snopek
Default Name
Edward E
Florian Breisch
Gero
GiulianoB
Javier Roman
Jay Horton
Jon Smith
Jonathan Turner
Jon Woodward
Justo Delgado Baudí
Jose Fernando Alexandre
Karl Werf
Kommentgames
Krzysztof Dluzniewski
Luke
Moonwards
Maciej Pendolski
Matthew Hillier
Mored1984
paul gruenbacher
Paul LaMotte
Péter Magyar
Rob Messick
Ross Esmond
Ryan Badour
Scott Wadden
Sergey
Shawn Yu
Svenne Krap
thechris
Tom Langwaldt
tukon
William Wold
Wyatt Goodin
Alex Khayrullin
Branwyn Tylwyth
Chris Goddard
Chris Serino
Christian Padilla
Conrad Curry
Craig Smith
Darrian Little
Dean Harmon
Ian Richard Kunert
Ivan Trombley
Joan Fons
Joshua Flores
Krzysztof Jankowski
Lord Bloodhound
Lucas Ferreira Franca
Michele Zilli
Nathan Lundquist
Nicklas Breum
Pascal Grüter
Petr Malac
Rami
@ -135,9 +146,10 @@ generous deed immortalized in the next stable release of Godot Engine.
Xavier PATRICELLI
Adam Neumann
Alessandra Pereyra
Alexander J Maynard
Alexey Dyadchenko
André Frélicot
andres eduardo lopez
Andrew Bowen
Asdf
Ben Botwin
@ -147,50 +159,48 @@ generous deed immortalized in the next stable release of Godot Engine.
Christoph Schröder
Cody Parker
D
Daniel
Daniel Eichler
David White
Deadly Lampshade
Eric
Eric Churches
Eric Monson
Eugenio Hugo Salgüero Jáñez
flesk
Francisco Javier Moreno Carracedo
gavlig
GGGames.org
Giles Montgomery
Guilherme Felipe de C. G. da Silva
Heath Hayes
Hysteria
Idzard Kwadijk
Jared White
Jesse Nave
Joe Flood
Jose Malheiro
Joshua Flores
Joshua Lesperance
Juan T Chen
Juraj Móza
Kasper Jeppesen
kinfox
Klaus The.
Klavdij Voncina
Leandro Voltolino
Maarten Elings
Marcelo Dornbusch Lopes
Markus Fehr
Markus Wiesner
Martin Eigel
Marvin
Matt Eunson
Matthew Hillier
Max Bulai
Max R.R. Collada
M H
Nick Nikitin
Oliver Dick
Paolo Munoz
Patrick Ting
Paul Hocker
Paul Von Zimmerman
Pete Goodwin
pl
Ranoller
Romildo Franco
Samuel Judd
Scott Pilet
spilldata
@ -198,60 +208,59 @@ generous deed immortalized in the next stable release of Godot Engine.
Thomas Krampl
Tobias Bocanegra
Urho
WytRabbit
Xavier Fumado Beltran
Zie Weaver
## Silver donors
1D_Inc
Abby Jones
Abraham Haskins
Adam Brunnmeier
Adam Carr
Adam Nakonieczny
Adam Smeltzer
Adisibio
Adrian Demetrescu
Aggelos Arnaoutis
Agustinus Arya
Aidan O'Flannagain
Albin Jonasson Svärdsby
Alder Stefano
Alessandro Senese
Alexander Gillberg
Alexander Koppe
Alex Davies-Moore
Alice Robinson
Allen Schade
Andreas Evers
Andreas Krampitz
Andreas Lundmark
Andreas Schüle
Andrew Peart
André Simões
Andrés Rodríguez
Andrzej Skalski
Anthony Bongiovanni
Anthony Staunton
Anton Kurkin
Antony K. Jones
AP Condomines
Arda Erol
Artem Bashev
Arthur S. Muszynski
Artistofdeath
Aubrey Falconer
Avencherus
B A
Balázs Batári
Bastian Böhm
Beliar
Benedikt
Ben Phelan
Ben Vercammen
Ben Woodley
Berbank
Bernd Jänichen
Black Block
Blair Allen
Bobby CC Wong
Boyquotes
Branwyn Tylwyth
Bryan Stevenson
Caleb Dumitry
Carwyn Edwards
Chris Brown
Chris Chapin
Chris Gonzales
Christian Baune
Christian Winter
Christoffer Sundbom
@ -260,18 +269,22 @@ generous deed immortalized in the next stable release of Godot Engine.
Cobaltum
Collin Shooltz
Dag Sundin Söderström
Dan H. Bentsen
Daniel Johnson
DanielMaximiano
Daniel Pontillo
Daniel Reed
Danny Welch
Dave Watts
Daniel Tebbutt
David Bullock
David Cravens
David May
Dimitri Stanojevic
David Rapisarda
David Woodard
Dominic Cooney
Dominik Wetzel
DrevanTonder
Donovan Hutcheon
Duobix
Eduardo Teixeira
Edward Herbert
Egon Elbre
Ellen Marie Dash
@ -280,18 +293,21 @@ generous deed immortalized in the next stable release of Godot Engine.
Eric Ellingson
Eric Martini
Eric Williams
EugeneTel
Evan Rose
Felix Kollmann
fengjiongmax
Flaredown
FuDiggity
G3Dev sàrl
Gadzhi Kharkharov
gamedev by Celio
Gary Hulst
Gerrit Großkopf
George Marques
gmmath
Grant Clarke
Greg Olson
Greg P
Greyson Richey
Guldoman
Hal A
Heribert Hirth
@ -299,7 +315,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Hunter Jones
Hylpher
ialex32x
Igor Buzatovic
Iiari
IndustrialRobot
Isaac Morton
@ -326,28 +341,33 @@ generous deed immortalized in the next stable release of Godot Engine.
Jon Bonazza
Jon Sully
Jose Aleman
Jose Andrés Mejias Rojas
Joseph Catrambone
Josh 'Cheeseness' Bush
Juanfran
Juan Negrier
Juan Velandia
Judd
Jueast
Julian Murgia
Kasier Bald0
Justin Spedding
Kaiser Bald0
Kamuna
Kauzig
KC Chan
Keedong Park
kickmaniac
Kiyohiro Kawamura (kyorohiro)
Kjetil Haugland
Klagsam
Klassix
KR McGinley
KsyTek Games
Kuan Cheang
kycho
Leviathan Hunter
Levi Lindsey
Linus Lind Lundgren
Lionel Gaillard
Luis Moraes
LunaticInAHat
Lurkars
Macil
@ -355,61 +375,75 @@ generous deed immortalized in the next stable release of Godot Engine.
Malcolm
Malik Ahmed
Malik Nejer
Marc Urlus
Marcus Richter
Markus Lohaus
Markus Michael Egger
Martin Holas
Martin Liška
Matt Edwards
Matthew Little
Maxwell
medecau
mhilbrunner
Michael Dürwald
Michael Gringauz
Michael Haney
Michael Labbe
Mikael Olsson
Mikayla Hutchinson
Mike Birkhead
Mike Cunningham
Mitchell J. Wagner
mlevin cantu
MoM
Moritz Laass
MuffinManKen
Nathan Fish
Natrim
nee
Neil Blakey-Milner
Nerdforge
Nicholas
Nicholas Bettencourt
Nick Macholl
Niclas Eriksen
Nicolás Montaña
Nicolas SAN AGUSTIN
Nima Farid
Nithin Jino
NZ
Olivier
Omar Delarosa
omzee
Oscar Norlander
Pafka
Pan Ip
Pat LaBine
Patrick Forringer
Patrick Nafarrete
Paul Gieske
Paul Mason
Paweł Kowal
Philip O. Staiger
Philip Cohoe
Pierre-Igor Berthet
Pietro Vertechi
Pitsanu Tongprasin
Point08
Poryg
Rafa Laguna
Rafal Wyszomirski
Raphael Leroux
Remi Rampin
Rémi Verschelde
Rezgi
Ricardo Alcantara
Robert Farr (Larington)
Robert Hernandez
Robert Larnach
Rodrigo Loli
Roger Smith
Roland Rząsa
Roman Tinkov
Ronan Jouchet
Ryan
Ryan Brooks
Ryan Groom
Ryan Hentz
Saad Khoudmi
@ -418,46 +452,51 @@ generous deed immortalized in the next stable release of Godot Engine.
Sasori Olkof
Scott D. Yelich
Sebastian Michailidis
sgnsajgon
Shane
Shane Sicienski
Shane Spoor
Simon Ledam
Simon Wenner
SK
Sootstone
Stonepyre
Thibault Barbaroux
Taylor Fahlman
thomas
Thomas Bell
Thomas Kelly
Thomas Kurz
tiansheng li
Tim
Tim Drumheller
Tim Gudex
Timo Schmidt
Timothy B. MacDonald
Tobbun
Tom Fulp
Tom Glenn
Tom Larrow
Torsten Crass
Travis O'Brien
Trent Skinner
Triptych
Troy Bonneau
Tryggve Sollid
Turgut Temucin
Tyler Stafos
UltyX
Vaiktorg
Valeria Viana Gusmao
Veodok
Victor
Vigilant Watch
Vincent Cloutier
waka nya
Walter Byers
Wayne Haak
werner mendizabal
Wiley Thompson
Will
William Hogben
Wout Standaert
Yeung Si Xiang
Wyatt Goodin
Yegor
蕭惟允
## Bronze donors

View file

@ -311,6 +311,10 @@ if selected_platform in platform_list:
# must happen after the flags, so when flags are used by configure, stuff happens (ie, ssl on x11)
detect.configure(env)
# Enable C++11 support
if not env.msvc:
env.Append(CXXFLAGS=['-std=c++11'])
# Configure compiler warnings
if env.msvc:
# Truncations, narrowing conversions, signed/unsigned comparisons...
@ -480,6 +484,13 @@ if selected_platform in platform_list:
if env['minizip']:
env.Append(CPPDEFINES=['MINIZIP_ENABLED'])
editor_module_list = ['regex']
for x in editor_module_list:
if not env['module_' + x + '_enabled']:
if env['tools']:
print("Build option 'module_" + x + "_enabled=no' cannot be used with 'tools=yes' (editor), only with 'tools=no' (export template).")
sys.exit(255)
if not env['verbose']:
methods.no_verbose(sys, env)

View file

@ -159,6 +159,7 @@ env.CommandNoCache('#core/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"]
# Chain load SCsubs
SConscript('os/SCsub')
SConscript('math/SCsub')
SConscript('crypto/SCsub')
SConscript('io/SCsub')
SConscript('bind/SCsub')

View file

@ -133,18 +133,12 @@ void Array::erase(const Variant &p_value) {
}
Variant Array::front() const {
if (_p->array.size() == 0) {
ERR_EXPLAIN("Can't take value from empty array");
ERR_FAIL_V(Variant());
}
ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");
return operator[](0);
}
Variant Array::back() const {
if (_p->array.size() == 0) {
ERR_EXPLAIN("Can't take value from empty array");
ERR_FAIL_V(Variant());
}
ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");
return operator[](_p->array.size() - 1);
}

View file

@ -30,11 +30,11 @@
#include "core_bind.h"
#include "core/crypto/crypto_core.h"
#include "core/io/file_access_compressed.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/json.h"
#include "core/io/marshalls.h"
#include "core/math/crypto_core.h"
#include "core/math/geometry.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@ -73,10 +73,7 @@ RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, bool
Error err = OK;
RES ret = ResourceLoader::load(p_path, p_type_hint, p_no_cache, &err);
if (err != OK) {
ERR_EXPLAIN("Error loading resource: '" + p_path + "'");
ERR_FAIL_V(ret);
}
ERR_FAIL_COND_V_MSG(err != OK, ret, "Error loading resource: '" + p_path + "'.");
return ret;
}
@ -148,10 +145,7 @@ _ResourceLoader::_ResourceLoader() {
}
Error _ResourceSaver::save(const String &p_path, const RES &p_resource, SaverFlags p_flags) {
if (p_resource.is_null()) {
ERR_EXPLAIN("Can't save empty resource to path: " + String(p_path))
ERR_FAIL_V(ERR_INVALID_PARAMETER);
}
ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path: " + String(p_path) + ".");
return ResourceSaver::save(p_path, p_resource, p_flags);
}
@ -191,10 +185,31 @@ _ResourceSaver::_ResourceSaver() {
/////////////////OS
void _OS::global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta) {
OS::get_singleton()->global_menu_add_item(p_menu, p_label, p_signal, p_meta);
}
void _OS::global_menu_add_separator(const String &p_menu) {
OS::get_singleton()->global_menu_add_separator(p_menu);
}
void _OS::global_menu_remove_item(const String &p_menu, int p_idx) {
OS::get_singleton()->global_menu_remove_item(p_menu, p_idx);
}
void _OS::global_menu_clear(const String &p_menu) {
OS::get_singleton()->global_menu_clear(p_menu);
}
Point2 _OS::get_mouse_position() const {
return OS::get_singleton()->get_mouse_position();
}
void _OS::set_window_title(const String &p_title) {
OS::get_singleton()->set_window_title(p_title);
@ -208,6 +223,7 @@ int _OS::get_mouse_button_state() const {
String _OS::get_unique_id() const {
return OS::get_singleton()->get_unique_id();
}
bool _OS::has_touchscreen_ui_hint() const {
return OS::get_singleton()->has_touchscreen_ui_hint();
@ -217,6 +233,7 @@ void _OS::set_clipboard(const String &p_text) {
OS::get_singleton()->set_clipboard(p_text);
}
String _OS::get_clipboard() const {
return OS::get_singleton()->get_clipboard();
@ -263,12 +280,14 @@ void _OS::set_video_mode(const Size2 &p_size, bool p_fullscreen, bool p_resizeab
vm.resizable = p_resizeable;
OS::get_singleton()->set_video_mode(vm, p_screen);
}
Size2 _OS::get_video_mode(int p_screen) const {
OS::VideoMode vm;
vm = OS::get_singleton()->get_video_mode(p_screen);
return Size2(vm.width, vm.height);
}
bool _OS::is_video_mode_fullscreen(int p_screen) const {
OS::VideoMode vm;
@ -727,22 +746,16 @@ int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const {
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
ERR_EXPLAIN("Invalid second value of: " + itos(second));
ERR_FAIL_COND_V(second > 59, 0);
ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + ".");
ERR_EXPLAIN("Invalid minute value of: " + itos(minute));
ERR_FAIL_COND_V(minute > 59, 0);
ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + ".");
ERR_EXPLAIN("Invalid hour value of: " + itos(hour));
ERR_FAIL_COND_V(hour > 23, 0);
ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + ".");
ERR_EXPLAIN("Invalid month value of: " + itos(month));
ERR_FAIL_COND_V(month > 12 || month == 0, 0);
ERR_FAIL_COND_V_MSG(month > 12 || month == 0, 0, "Invalid month value of: " + itos(month) + ".");
// Do this check after month is tested as valid
ERR_EXPLAIN("Invalid day value of: " + itos(day) + " which is larger than " + itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]) + " or 0");
ERR_FAIL_COND_V(day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1] || day == 0, 0);
ERR_FAIL_COND_V_MSG(day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1] || day == 0, 0, "Invalid day value of: " + itos(day) + " which is larger than " + itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]) + " or 0.");
// Calculate all the seconds from months past in this year
uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY;
@ -1137,6 +1150,11 @@ void _OS::_bind_methods() {
//ClassDB::bind_method(D_METHOD("is_video_mode_resizable","screen"),&_OS::is_video_mode_resizable,DEFVAL(0));
//ClassDB::bind_method(D_METHOD("get_fullscreen_mode_list","screen"),&_OS::get_fullscreen_mode_list,DEFVAL(0));
ClassDB::bind_method(D_METHOD("global_menu_add_item", "menu", "label", "id", "meta"), &_OS::global_menu_add_item);
ClassDB::bind_method(D_METHOD("global_menu_add_separator", "menu"), &_OS::global_menu_add_separator);
ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu", "idx"), &_OS::global_menu_remove_item);
ClassDB::bind_method(D_METHOD("global_menu_clear", "menu"), &_OS::global_menu_clear);
ClassDB::bind_method(D_METHOD("get_video_driver_count"), &_OS::get_video_driver_count);
ClassDB::bind_method(D_METHOD("get_video_driver_name", "driver"), &_OS::get_video_driver_name);
ClassDB::bind_method(D_METHOD("get_current_video_driver"), &_OS::get_current_video_driver);
@ -1414,6 +1432,11 @@ PoolVector<Plane> _Geometry::build_capsule_planes(float p_radius, float p_height
return Geometry::build_capsule_planes(p_radius, p_height, p_sides, p_lats, p_axis);
}
bool _Geometry::is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius) {
return Geometry::is_point_in_circle(p_point, p_circle_pos, p_circle_radius);
}
real_t _Geometry::segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius) {
return Geometry::segment_intersects_circle(p_from, p_to, p_circle_pos, p_circle_radius);
@ -1666,11 +1689,6 @@ Array _Geometry::offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_d
return ret;
}
Vector<Point2> _Geometry::transform_points_2d(const Vector<Point2> &p_points, const Transform2D &p_mat) {
return Geometry::transform_points_2d(p_points, p_mat);
}
Dictionary _Geometry::make_atlas(const Vector<Size2> &p_rects) {
Dictionary ret;
@ -1709,6 +1727,7 @@ void _Geometry::_bind_methods() {
ClassDB::bind_method(D_METHOD("build_box_planes", "extents"), &_Geometry::build_box_planes);
ClassDB::bind_method(D_METHOD("build_cylinder_planes", "radius", "height", "sides", "axis"), &_Geometry::build_cylinder_planes, DEFVAL(Vector3::AXIS_Z));
ClassDB::bind_method(D_METHOD("build_capsule_planes", "radius", "height", "sides", "lats", "axis"), &_Geometry::build_capsule_planes, DEFVAL(Vector3::AXIS_Z));
ClassDB::bind_method(D_METHOD("is_point_in_circle", "point", "circle_position", "circle_radius"), &_Geometry::is_point_in_circle);
ClassDB::bind_method(D_METHOD("segment_intersects_circle", "segment_from", "segment_to", "circle_position", "circle_radius"), &_Geometry::segment_intersects_circle);
ClassDB::bind_method(D_METHOD("segment_intersects_segment_2d", "from_a", "to_a", "from_b", "to_b"), &_Geometry::segment_intersects_segment_2d);
ClassDB::bind_method(D_METHOD("line_intersects_line_2d", "from_a", "dir_a", "from_b", "dir_b"), &_Geometry::line_intersects_line_2d);
@ -1749,8 +1768,6 @@ void _Geometry::_bind_methods() {
ClassDB::bind_method(D_METHOD("offset_polygon_2d", "polygon", "delta", "join_type"), &_Geometry::offset_polygon_2d, DEFVAL(JOIN_SQUARE));
ClassDB::bind_method(D_METHOD("offset_polyline_2d", "polyline", "delta", "join_type", "end_type"), &_Geometry::offset_polyline_2d, DEFVAL(JOIN_SQUARE), DEFVAL(END_SQUARE));
ClassDB::bind_method(D_METHOD("transform_points_2d", "points", "transform"), &_Geometry::transform_points_2d);
ClassDB::bind_method(D_METHOD("make_atlas", "sizes"), &_Geometry::make_atlas);
BIND_ENUM_CONSTANT(OPERATION_UNION);
@ -2621,8 +2638,7 @@ void _Thread::_start_func(void *ud) {
}
}
ERR_EXPLAIN("Could not call function '" + t->target_method.operator String() + "'' starting thread ID: " + t->get_id() + " Reason: " + reason);
ERR_FAIL();
ERR_FAIL_MSG("Could not call function '" + t->target_method.operator String() + "'' starting thread ID: " + t->get_id() + " Reason: " + reason + ".");
}
}
@ -2704,10 +2720,7 @@ _Thread::_Thread() {
_Thread::~_Thread() {
if (active) {
ERR_EXPLAIN("Reference to a Thread object object was lost while the thread is still running...");
}
ERR_FAIL_COND(active);
ERR_FAIL_COND_MSG(active, "Reference to a Thread object object was lost while the thread is still running...");
}
/////////////////////////////////////

View file

@ -109,11 +109,11 @@ public:
};
enum PowerState {
POWERSTATE_UNKNOWN, /**< cannot determine power status */
POWERSTATE_ON_BATTERY, /**< Not plugged in, running on the battery */
POWERSTATE_NO_BATTERY, /**< Plugged in, no battery available */
POWERSTATE_CHARGING, /**< Plugged in, charging battery */
POWERSTATE_CHARGED /**< Plugged in, battery charged */
POWERSTATE_UNKNOWN, // Cannot determine power status.
POWERSTATE_ON_BATTERY, // Not plugged in, running on the battery.
POWERSTATE_NO_BATTERY, // Plugged in, no battery available.
POWERSTATE_CHARGING, // Plugged in, charging battery.
POWERSTATE_CHARGED // Plugged in, battery charged.
};
enum Weekday {
@ -127,8 +127,8 @@ public:
};
enum Month {
/// Start at 1 to follow Windows SYSTEMTIME structure
/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
// Start at 1 to follow Windows SYSTEMTIME structure
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
MONTH_JANUARY = 1,
MONTH_FEBRUARY,
MONTH_MARCH,
@ -143,6 +143,11 @@ public:
MONTH_DECEMBER
};
void global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta);
void global_menu_add_separator(const String &p_menu);
void global_menu_remove_item(const String &p_menu, int p_idx);
void global_menu_clear(const String &p_menu);
Point2 get_mouse_position() const;
void set_window_title(const String &p_title);
int get_mouse_button_state() const;
@ -259,24 +264,6 @@ public:
bool is_scancode_unicode(uint32_t p_unicode) const;
int find_scancode_from_string(const String &p_code) const;
/*
struct Date {
int year;
Month month;
int day;
Weekday weekday;
bool dst;
};
struct Time {
int hour;
int min;
int sec;
};
*/
void set_use_file_access_save_and_swap(bool p_enable);
void set_native_icon(const String &p_filename);
@ -404,6 +391,7 @@ public:
PoolVector<Vector3> segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius);
PoolVector<Vector3> segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius);
PoolVector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Vector<Plane> &p_planes);
bool is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius);
real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius);
int get_uv84_normal_bit(const Vector3 &p_vector);
@ -420,17 +408,17 @@ public:
OPERATION_INTERSECTION,
OPERATION_XOR
};
// 2D polygon boolean operations
Array merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // union (add)
Array clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // difference (subtract)
Array intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // common area (multiply)
Array exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // all but common area (xor)
// 2D polygon boolean operations.
Array merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add).
Array clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract).
Array intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
Array exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).
// 2D polyline vs polygon operations
Array clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // cut
Array intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // chop
// 2D polyline vs polygon operations.
Array clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
Array intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.
// 2D offset polygons/polylines
// 2D offset polygons/polylines.
enum PolyJoinType {
JOIN_SQUARE,
JOIN_ROUND,
@ -446,8 +434,6 @@ public:
Array offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE);
Array offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE);
Vector<Point2> transform_points_2d(const Vector<Point2> &p_points, const Transform2D &p_mat);
Dictionary make_atlas(const Vector<Size2> &p_rects);
_Geometry();
@ -486,24 +472,24 @@ public:
Error open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
Error open(const String &p_path, ModeFlags p_mode_flags); ///< open a file
void close(); ///< close a file
bool is_open() const; ///< true when file is open
Error open(const String &p_path, ModeFlags p_mode_flags); // open a file.
void close(); // Close a file.
bool is_open() const; // True when file is open.
String get_path() const; /// returns the path for the current open file
String get_path_absolute() const; /// returns the absolute path for the current open file
String get_path() const; // Returns the path for the current open file.
String get_path_absolute() const; // Returns the absolute path for the current open file.
void seek(int64_t p_position); ///< seek to a given position
void seek_end(int64_t p_position = 0); ///< seek from the end of file
int64_t get_position() const; ///< get position in the file
int64_t get_len() const; ///< get size of the file
void seek(int64_t p_position); // Seek to a given position.
void seek_end(int64_t p_position = 0); // Seek from the end of file.
int64_t get_position() const; // Get position in the file.
int64_t get_len() const; // Get size of the file.
bool eof_reached() const; ///< reading passed EOF
bool eof_reached() const; // Reading passed EOF.
uint8_t get_8() const; ///< get a byte
uint16_t get_16() const; ///< get 16 bits uint
uint32_t get_32() const; ///< get 32 bits uint
uint64_t get_64() const; ///< get 64 bits uint
uint8_t get_8() const; // Get a byte.
uint16_t get_16() const; // Get 16 bits uint.
uint32_t get_32() const; // Get 32 bits uint.
uint64_t get_64() const; // Get 64 bits uint.
float get_float() const;
double get_double() const;
@ -511,27 +497,27 @@ public:
Variant get_var(bool p_allow_objects = false) const;
PoolVector<uint8_t> get_buffer(int p_length) const; ///< get an array of bytes
PoolVector<uint8_t> get_buffer(int p_length) const; // Get an array of bytes.
String get_line() const;
Vector<String> get_csv_line(const String &p_delim = ",") const;
String get_as_text() const;
String get_md5(const String &p_path) const;
String get_sha256(const String &p_path) const;
/**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac)
/* Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac).
* It's not about the current CPU type but file formats.
* this flags get reset to false (little endian) on each open
* This flags get reset to false (little endian) on each open.
*/
void set_endian_swap(bool p_swap);
bool get_endian_swap();
Error get_error() const; ///< get last error
Error get_error() const; // Get last error.
void store_8(uint8_t p_dest); ///< store a byte
void store_16(uint16_t p_dest); ///< store 16 bits uint
void store_32(uint32_t p_dest); ///< store 32 bits uint
void store_64(uint64_t p_dest); ///< store 64 bits uint
void store_8(uint8_t p_dest); // Store a byte.
void store_16(uint16_t p_dest); // Store 16 bits uint.
void store_32(uint32_t p_dest); // Store 32 bits uint.
void store_64(uint64_t p_dest); // Store 64 bits uint.
void store_float(float p_dest);
void store_double(double p_dest);
@ -544,11 +530,11 @@ public:
virtual void store_pascal_string(const String &p_string);
virtual String get_pascal_string();
void store_buffer(const PoolVector<uint8_t> &p_buffer); ///< store an array of bytes
void store_buffer(const PoolVector<uint8_t> &p_buffer); // Store an array of bytes.
void store_var(const Variant &p_var, bool p_full_objects = false);
bool file_exists(const String &p_name) const; ///< return true if a file exists
bool file_exists(const String &p_name) const; // Return true if a file exists.
uint64_t get_modified_time(const String &p_file) const;
@ -570,18 +556,18 @@ protected:
public:
Error open(const String &p_path);
Error list_dir_begin(bool p_skip_navigational = false, bool p_skip_hidden = false); ///< This starts dir listing
Error list_dir_begin(bool p_skip_navigational = false, bool p_skip_hidden = false); // This starts dir listing.
String get_next();
bool current_is_dir() const;
void list_dir_end(); ///<
void list_dir_end();
int get_drive_count();
String get_drive(int p_drive);
int get_current_drive();
Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
String get_current_dir(); ///< return current dir location
Error change_dir(String p_dir); // Can be relative or absolute, return false on success.
String get_current_dir(); // Return current dir location.
Error make_dir(String p_dir);
Error make_dir_recursive(String p_dir);

View file

@ -480,6 +480,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
for (List<StringName>::Element *F = snames.front(); F; F = F->next()) {
PropertySetGet *psg = t->property_setget.getptr(F->get());
ERR_FAIL_COND_V(!psg, 0);
hash = hash_djb2_one_64(F->get().hash(), hash);
hash = hash_djb2_one_64(psg->setter.hash(), hash);
@ -835,10 +836,7 @@ void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) {
#ifdef DEBUG_METHODS_ENABLED
ClassInfo *check = type;
while (check) {
if (check->signal_map.has(sname)) {
ERR_EXPLAIN("Type " + String(p_class) + " already has signal: " + String(sname));
ERR_FAIL();
}
ERR_FAIL_COND_MSG(check->signal_map.has(sname), "Type " + String(p_class) + " already has signal: " + String(sname) + ".");
check = check->inherits_ptr;
}
#endif
@ -923,16 +921,11 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons
if (p_setter) {
mb_set = get_method(p_class, p_setter);
#ifdef DEBUG_METHODS_ENABLED
if (!mb_set) {
ERR_EXPLAIN("Invalid Setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name);
ERR_FAIL();
} else {
int exp_args = 1 + (p_index >= 0 ? 1 : 0);
if (mb_set->get_argument_count() != exp_args) {
ERR_EXPLAIN("Invalid Function for Setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name);
ERR_FAIL();
}
}
ERR_FAIL_COND_MSG(!mb_set, "Invalid setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name + ".");
int exp_args = 1 + (p_index >= 0 ? 1 : 0);
ERR_FAIL_COND_MSG(mb_set->get_argument_count() != exp_args, "Invalid function for setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name + ".");
#endif
}
@ -942,25 +935,15 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons
mb_get = get_method(p_class, p_getter);
#ifdef DEBUG_METHODS_ENABLED
if (!mb_get) {
ERR_EXPLAIN("Invalid Getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name);
ERR_FAIL();
} else {
ERR_FAIL_COND_MSG(!mb_get, "Invalid getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name + ".");
int exp_args = 0 + (p_index >= 0 ? 1 : 0);
if (mb_get->get_argument_count() != exp_args) {
ERR_EXPLAIN("Invalid Function for Getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name);
ERR_FAIL();
}
}
int exp_args = 0 + (p_index >= 0 ? 1 : 0);
ERR_FAIL_COND_MSG(mb_get->get_argument_count() != exp_args, "Invalid function for getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name + ".");
#endif
}
#ifdef DEBUG_METHODS_ENABLED
if (type->property_setget.has(p_pinfo.name)) {
ERR_EXPLAIN("Object " + p_class + " already has property: " + p_pinfo.name);
ERR_FAIL();
}
ERR_FAIL_COND_MSG(type->property_setget.has(p_pinfo.name), "Object " + p_class + " already has property: " + p_pinfo.name + ".");
#endif
OBJTYPE_WLOCK
@ -1239,32 +1222,26 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const c
#ifdef DEBUG_ENABLED
if (has_method(instance_type, mdname)) {
ERR_EXPLAIN("Class " + String(instance_type) + " already has a method " + String(mdname));
ERR_FAIL_V(NULL);
}
ERR_FAIL_COND_V_MSG(has_method(instance_type, mdname), NULL, "Class " + String(instance_type) + " already has a method " + String(mdname) + ".");
#endif
ClassInfo *type = classes.getptr(instance_type);
if (!type) {
ERR_PRINTS("Couldn't bind method '" + mdname + "' for instance: " + instance_type);
memdelete(p_bind);
ERR_FAIL_V(NULL);
ERR_FAIL_V_MSG(NULL, "Couldn't bind method '" + mdname + "' for instance: " + instance_type + ".");
}
if (type->method_map.has(mdname)) {
memdelete(p_bind);
// overloading not supported
ERR_EXPLAIN("Method already bound: " + instance_type + "::" + mdname);
ERR_FAIL_V(NULL);
ERR_FAIL_V_MSG(NULL, "Method already bound: " + instance_type + "::" + mdname + ".");
}
#ifdef DEBUG_METHODS_ENABLED
if (method_name.args.size() > p_bind->get_argument_count()) {
memdelete(p_bind);
ERR_EXPLAIN("Method definition provides more arguments than the method actually has: " + instance_type + "::" + mdname);
ERR_FAIL_V(NULL);
ERR_FAIL_V_MSG(NULL, "Method definition provides more arguments than the method actually has: " + instance_type + "::" + mdname + ".");
}
p_bind->set_argument_names(method_name.args);

View file

@ -35,10 +35,6 @@
#include "core/object.h"
#include "core/print_string.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
/** To bind more then 6 parameters include this:
* #include "core/method_bind_ext.gen.inc"
*/
@ -310,8 +306,7 @@ public:
if (type->method_map.has(p_name)) {
memdelete(bind);
// overloading not supported
ERR_EXPLAIN("Method already bound: " + instance_type + "::" + p_name);
ERR_FAIL_V(NULL);
ERR_FAIL_V_MSG(NULL, "Method already bound: " + instance_type + "::" + p_name + ".");
}
type->method_map[p_name] = bind;
#ifdef DEBUG_METHODS_ENABLED

View file

@ -335,36 +335,23 @@ Color Color::html(const String &p_color) {
} else if (color.length() == 6) {
alpha = false;
} else {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
ERR_FAIL_V(Color());
ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_color + ".");
}
int a = 255;
if (alpha) {
a = _parse_col(color, 0);
if (a < 0) {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
ERR_FAIL_V(Color());
}
ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_color + ".");
}
int from = alpha ? 2 : 0;
int r = _parse_col(color, from + 0);
if (r < 0) {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
ERR_FAIL_V(Color());
}
ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_color + ".");
int g = _parse_col(color, from + 2);
if (g < 0) {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
ERR_FAIL_V(Color());
}
ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_color + ".");
int b = _parse_col(color, from + 4);
if (b < 0) {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
ERR_FAIL_V(Color());
}
ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_color + ".");
return Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
}
@ -425,12 +412,8 @@ Color Color::named(const String &p_name) {
name = name.to_lower();
const Map<String, Color>::Element *color = _named_colors.find(name);
if (color) {
return color->value();
} else {
ERR_EXPLAIN("Invalid Color Name: " + p_name);
ERR_FAIL_V(Color());
}
ERR_FAIL_NULL_V_MSG(color, Color(), "Invalid color name: " + p_name + ".");
return color->value();
}
String _to_hex(float p_val) {
@ -523,8 +506,7 @@ Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const {
// FIXME: Remove once Godot 3.1 has been released
float Color::gray() const {
ERR_EXPLAIN("Color.gray() is deprecated and will be removed in a future version. Use Color.get_v() for a better grayscale approximation.");
WARN_DEPRECATED;
WARN_DEPRECATED_MSG("Color.gray() is deprecated and will be removed in a future version. Use Color.get_v() for a better grayscale approximation.");
return (r + g + b) / 3.0;
}

View file

@ -33,9 +33,7 @@
#include "core/math/math_funcs.h"
#include "core/ustring.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
struct Color {
union {

View file

@ -37,10 +37,6 @@
#include "core/simple_type.h"
#include "core/typedefs.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
#define COMMA(N) _COMMA_##N
#define _COMMA_0
#define _COMMA_1 ,

38
core/crypto/SCsub Normal file
View file

@ -0,0 +1,38 @@
#!/usr/bin/env python
Import('env')
env_crypto = env.Clone()
is_builtin = env["builtin_mbedtls"]
has_module = env["module_mbedtls_enabled"]
if is_builtin or not has_module:
# Use our headers for builtin or if the module is not going to be compiled.
# We decided not to depend on system mbedtls just for these few files that can
# be easily extracted.
env_crypto.Prepend(CPPPATH=["#thirdparty/mbedtls/include"])
# MbedTLS core functions (for CryptoCore).
# If the mbedtls module is compiled we don't need to add the .c files with our
# custom config since they will be built by the module itself.
# Only if the module is not enabled, we must compile here the required sources
# to make a "light" build with only the necessary mbedtls files.
if not has_module:
env_thirdparty = env_crypto.Clone()
env_thirdparty.disable_warnings()
# Custom config file
env_thirdparty.Append(CPPDEFINES=[('MBEDTLS_CONFIG_FILE', '\\"thirdparty/mbedtls/include/godot_core_mbedtls_config.h\\"')])
thirdparty_mbedtls_dir = "#thirdparty/mbedtls/library/"
thirdparty_mbedtls_sources = [
"aes.c",
"base64.c",
"md5.c",
"sha1.c",
"sha256.c",
"godot_core_mbedtls_platform.c"
]
thirdparty_mbedtls_sources = [thirdparty_mbedtls_dir + file for file in thirdparty_mbedtls_sources]
env_thirdparty.add_source_files(env.core_sources, thirdparty_mbedtls_sources)
env_crypto.add_source_files(env.core_sources, "*.cpp")

170
core/crypto/crypto.cpp Normal file
View file

@ -0,0 +1,170 @@
/*************************************************************************/
/* crypto.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* 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. */
/*************************************************************************/
#include "crypto.h"
#include "core/engine.h"
#include "core/io/certs_compressed.gen.h"
#include "core/io/compression.h"
/// Resources
CryptoKey *(*CryptoKey::_create)() = NULL;
CryptoKey *CryptoKey::create() {
if (_create)
return _create();
return NULL;
}
void CryptoKey::_bind_methods() {
ClassDB::bind_method(D_METHOD("save", "path"), &CryptoKey::save);
ClassDB::bind_method(D_METHOD("load", "path"), &CryptoKey::load);
}
X509Certificate *(*X509Certificate::_create)() = NULL;
X509Certificate *X509Certificate::create() {
if (_create)
return _create();
return NULL;
}
void X509Certificate::_bind_methods() {
ClassDB::bind_method(D_METHOD("save", "path"), &X509Certificate::save);
ClassDB::bind_method(D_METHOD("load", "path"), &X509Certificate::load);
}
/// Crypto
void (*Crypto::_load_default_certificates)(String p_path) = NULL;
Crypto *(*Crypto::_create)() = NULL;
Crypto *Crypto::create() {
if (_create)
return _create();
return memnew(Crypto);
}
void Crypto::load_default_certificates(String p_path) {
if (_load_default_certificates)
_load_default_certificates(p_path);
}
void Crypto::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_random_bytes", "size"), &Crypto::generate_random_bytes);
ClassDB::bind_method(D_METHOD("generate_rsa", "size"), &Crypto::generate_rsa);
ClassDB::bind_method(D_METHOD("generate_self_signed_certificate", "key", "issuer_name", "not_before", "not_after"), &Crypto::generate_self_signed_certificate, DEFVAL("CN=myserver,O=myorganisation,C=IT"), DEFVAL("20140101000000"), DEFVAL("20340101000000"));
}
PoolByteArray Crypto::generate_random_bytes(int p_bytes) {
ERR_FAIL_V_MSG(PoolByteArray(), "generate_random_bytes is not available when mbedtls module is disabled.");
}
Ref<CryptoKey> Crypto::generate_rsa(int p_bytes) {
ERR_FAIL_V_MSG(NULL, "generate_rsa is not available when mbedtls module is disabled.");
}
Ref<X509Certificate> Crypto::generate_self_signed_certificate(Ref<CryptoKey> p_key, String p_issuer_name, String p_not_before, String p_not_after) {
ERR_FAIL_V_MSG(NULL, "generate_self_signed_certificate is not available when mbedtls module is disabled.");
}
Crypto::Crypto() {
}
/// Resource loader/saver
RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error) {
String el = p_path.get_extension().to_lower();
if (el == "crt") {
X509Certificate *cert = X509Certificate::create();
if (cert)
cert->load(p_path);
return cert;
} else if (el == "key") {
CryptoKey *key = CryptoKey::create();
if (key)
key->load(p_path);
return key;
}
return NULL;
}
void ResourceFormatLoaderCrypto::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("crt");
p_extensions->push_back("key");
}
bool ResourceFormatLoaderCrypto::handles_type(const String &p_type) const {
return p_type == "X509Certificate" || p_type == "CryptoKey";
}
String ResourceFormatLoaderCrypto::get_resource_type(const String &p_path) const {
String el = p_path.get_extension().to_lower();
if (el == "crt")
return "X509Certificate";
else if (el == "key")
return "CryptoKey";
return "";
}
Error ResourceFormatSaverCrypto::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
Error err;
Ref<X509Certificate> cert = p_resource;
Ref<CryptoKey> key = p_resource;
if (cert.is_valid()) {
err = cert->save(p_path);
} else if (key.is_valid()) {
err = key->save(p_path);
} else {
ERR_FAIL_V(ERR_INVALID_PARAMETER);
}
ERR_FAIL_COND_V(err != OK, err);
return OK;
}
void ResourceFormatSaverCrypto::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
const X509Certificate *cert = Object::cast_to<X509Certificate>(*p_resource);
const CryptoKey *key = Object::cast_to<CryptoKey>(*p_resource);
if (cert) {
p_extensions->push_back("crt");
}
if (key) {
p_extensions->push_back("key");
}
}
bool ResourceFormatSaverCrypto::recognize(const RES &p_resource) const {
return Object::cast_to<X509Certificate>(*p_resource) || Object::cast_to<CryptoKey>(*p_resource);
}

105
core/crypto/crypto.h Normal file
View file

@ -0,0 +1,105 @@
/*************************************************************************/
/* crypto.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* 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. */
/*************************************************************************/
#ifndef CRYPTO_H
#define CRYPTO_H
#include "core/reference.h"
#include "core/resource.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
class CryptoKey : public Resource {
GDCLASS(CryptoKey, Resource);
protected:
static void _bind_methods();
static CryptoKey *(*_create)();
public:
static CryptoKey *create();
virtual Error load(String p_path) = 0;
virtual Error save(String p_path) = 0;
};
class X509Certificate : public Resource {
GDCLASS(X509Certificate, Resource);
protected:
static void _bind_methods();
static X509Certificate *(*_create)();
public:
static X509Certificate *create();
virtual Error load(String p_path) = 0;
virtual Error load_from_memory(const uint8_t *p_buffer, int p_len) = 0;
virtual Error save(String p_path) = 0;
};
class Crypto : public Reference {
GDCLASS(Crypto, Reference);
protected:
static void _bind_methods();
static Crypto *(*_create)();
static void (*_load_default_certificates)(String p_path);
public:
static Crypto *create();
static void load_default_certificates(String p_path);
virtual PoolByteArray generate_random_bytes(int p_bytes);
virtual Ref<CryptoKey> generate_rsa(int p_bytes);
virtual Ref<X509Certificate> generate_self_signed_certificate(Ref<CryptoKey> p_key, String p_issuer_name, String p_not_before, String p_not_after);
Crypto();
};
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
GDCLASS(ResourceFormatLoaderCrypto, ResourceFormatLoader);
public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
};
class ResourceFormatSaverCrypto : public ResourceFormatSaver {
GDCLASS(ResourceFormatSaverCrypto, ResourceFormatSaver);
public:
virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
virtual bool recognize(const RES &p_resource) const;
};
#endif // CRYPTO_H

View file

@ -52,7 +52,7 @@ Error CryptoCore::MD5Context::start() {
return ret ? FAILED : OK;
}
Error CryptoCore::MD5Context::update(uint8_t *p_src, size_t p_len) {
Error CryptoCore::MD5Context::update(const uint8_t *p_src, size_t p_len) {
int ret = mbedtls_md5_update_ret((mbedtls_md5_context *)ctx, p_src, p_len);
return ret ? FAILED : OK;
}
@ -62,6 +62,32 @@ Error CryptoCore::MD5Context::finish(unsigned char r_hash[16]) {
return ret ? FAILED : OK;
}
// SHA1
CryptoCore::SHA1Context::SHA1Context() {
ctx = memalloc(sizeof(mbedtls_sha1_context));
mbedtls_sha1_init((mbedtls_sha1_context *)ctx);
}
CryptoCore::SHA1Context::~SHA1Context() {
mbedtls_sha1_free((mbedtls_sha1_context *)ctx);
memfree((mbedtls_sha1_context *)ctx);
}
Error CryptoCore::SHA1Context::start() {
int ret = mbedtls_sha1_starts_ret((mbedtls_sha1_context *)ctx);
return ret ? FAILED : OK;
}
Error CryptoCore::SHA1Context::update(const uint8_t *p_src, size_t p_len) {
int ret = mbedtls_sha1_update_ret((mbedtls_sha1_context *)ctx, p_src, p_len);
return ret ? FAILED : OK;
}
Error CryptoCore::SHA1Context::finish(unsigned char r_hash[20]) {
int ret = mbedtls_sha1_finish_ret((mbedtls_sha1_context *)ctx, r_hash);
return ret ? FAILED : OK;
}
// SHA256
CryptoCore::SHA256Context::SHA256Context() {
ctx = memalloc(sizeof(mbedtls_sha256_context));
@ -78,12 +104,12 @@ Error CryptoCore::SHA256Context::start() {
return ret ? FAILED : OK;
}
Error CryptoCore::SHA256Context::update(uint8_t *p_src, size_t p_len) {
Error CryptoCore::SHA256Context::update(const uint8_t *p_src, size_t p_len) {
int ret = mbedtls_sha256_update_ret((mbedtls_sha256_context *)ctx, p_src, p_len);
return ret ? FAILED : OK;
}
Error CryptoCore::SHA256Context::finish(unsigned char r_hash[16]) {
Error CryptoCore::SHA256Context::finish(unsigned char r_hash[32]) {
int ret = mbedtls_sha256_finish_ret((mbedtls_sha256_context *)ctx, r_hash);
return ret ? FAILED : OK;
}

View file

@ -46,10 +46,24 @@ public:
~MD5Context();
Error start();
Error update(uint8_t *p_src, size_t p_len);
Error update(const uint8_t *p_src, size_t p_len);
Error finish(unsigned char r_hash[16]);
};
class SHA1Context {
private:
void *ctx; // To include, or not to include...
public:
SHA1Context();
~SHA1Context();
Error start();
Error update(const uint8_t *p_src, size_t p_len);
Error finish(unsigned char r_hash[20]);
};
class SHA256Context {
private:
@ -60,8 +74,8 @@ public:
~SHA256Context();
Error start();
Error update(uint8_t *p_src, size_t p_len);
Error finish(unsigned char r_hash[16]);
Error update(const uint8_t *p_src, size_t p_len);
Error finish(unsigned char r_hash[32]);
};
class AESContext {

View file

@ -0,0 +1,137 @@
/*************************************************************************/
/* hashing_context.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* 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. */
/*************************************************************************/
#include "hashing_context.h"
#include "core/crypto/crypto_core.h"
Error HashingContext::start(HashType p_type) {
ERR_FAIL_COND_V(ctx != NULL, ERR_ALREADY_IN_USE);
_create_ctx(p_type);
ERR_FAIL_COND_V(ctx == NULL, ERR_UNAVAILABLE);
switch (type) {
case HASH_MD5:
return ((CryptoCore::MD5Context *)ctx)->start();
case HASH_SHA1:
return ((CryptoCore::SHA1Context *)ctx)->start();
case HASH_SHA256:
return ((CryptoCore::SHA256Context *)ctx)->start();
}
return ERR_UNAVAILABLE;
}
Error HashingContext::update(PoolByteArray p_chunk) {
ERR_FAIL_COND_V(ctx == NULL, ERR_UNCONFIGURED);
size_t len = p_chunk.size();
PoolByteArray::Read r = p_chunk.read();
switch (type) {
case HASH_MD5:
return ((CryptoCore::MD5Context *)ctx)->update(&r[0], len);
case HASH_SHA1:
return ((CryptoCore::SHA1Context *)ctx)->update(&r[0], len);
case HASH_SHA256:
return ((CryptoCore::SHA256Context *)ctx)->update(&r[0], len);
}
return ERR_UNAVAILABLE;
}
PoolByteArray HashingContext::finish() {
ERR_FAIL_COND_V(ctx == NULL, PoolByteArray());
PoolByteArray out;
Error err = FAILED;
switch (type) {
case HASH_MD5:
out.resize(16);
err = ((CryptoCore::MD5Context *)ctx)->finish(out.write().ptr());
break;
case HASH_SHA1:
out.resize(20);
err = ((CryptoCore::SHA1Context *)ctx)->finish(out.write().ptr());
break;
case HASH_SHA256:
out.resize(32);
err = ((CryptoCore::SHA256Context *)ctx)->finish(out.write().ptr());
break;
}
_delete_ctx();
ERR_FAIL_COND_V(err != OK, PoolByteArray());
return out;
}
void HashingContext::_create_ctx(HashType p_type) {
type = p_type;
switch (type) {
case HASH_MD5:
ctx = memnew(CryptoCore::MD5Context);
break;
case HASH_SHA1:
ctx = memnew(CryptoCore::SHA1Context);
break;
case HASH_SHA256:
ctx = memnew(CryptoCore::SHA256Context);
break;
default:
ctx = NULL;
}
}
void HashingContext::_delete_ctx() {
return;
switch (type) {
case HASH_MD5:
memdelete((CryptoCore::MD5Context *)ctx);
break;
case HASH_SHA1:
memdelete((CryptoCore::SHA1Context *)ctx);
break;
case HASH_SHA256:
memdelete((CryptoCore::SHA256Context *)ctx);
break;
}
ctx = NULL;
}
void HashingContext::_bind_methods() {
ClassDB::bind_method(D_METHOD("start", "type"), &HashingContext::start);
ClassDB::bind_method(D_METHOD("update", "chunk"), &HashingContext::update);
ClassDB::bind_method(D_METHOD("finish"), &HashingContext::finish);
BIND_ENUM_CONSTANT(HASH_MD5);
BIND_ENUM_CONSTANT(HASH_SHA1);
BIND_ENUM_CONSTANT(HASH_SHA256);
}
HashingContext::HashingContext() {
ctx = NULL;
}
HashingContext::~HashingContext() {
if (ctx != NULL)
_delete_ctx();
}

View file

@ -0,0 +1,66 @@
/*************************************************************************/
/* hashing_context.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* 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. */
/*************************************************************************/
#ifndef HASHING_CONTEXT_H
#define HASHING_CONTEXT_H
#include "core/reference.h"
class HashingContext : public Reference {
GDCLASS(HashingContext, Reference);
public:
enum HashType {
HASH_MD5,
HASH_SHA1,
HASH_SHA256
};
private:
void *ctx;
HashType type;
protected:
static void _bind_methods();
void _create_ctx(HashType p_type);
void _delete_ctx();
public:
Error start(HashType p_type);
Error update(PoolByteArray p_chunk);
PoolByteArray finish();
HashingContext();
~HashingContext();
};
VARIANT_ENUM_CAST(HashingContext::HashType);
#endif // HASHING_CONTEXT_H

View file

@ -197,10 +197,7 @@ void Engine::add_singleton(const Singleton &p_singleton) {
Object *Engine::get_singleton_object(const String &p_name) const {
const Map<StringName, Object *>::Element *E = singleton_ptrs.find(p_name);
if (!E) {
ERR_EXPLAIN("Failed to retrieve non-existent singleton '" + p_name + "'");
ERR_FAIL_V(NULL);
}
ERR_FAIL_COND_V_MSG(!E, NULL, "Failed to retrieve non-existent singleton '" + p_name + "'.");
return E->get();
};

View file

@ -140,6 +140,16 @@ extern bool _err_error_exists;
_err_error_exists = false; \
} while (0); // (*)
#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \
do { \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
ERR_EXPLAIN(m_msg); \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return; \
} \
_err_error_exists = false; \
} while (0); // (*)
/** An index has failed if m_index<0 or m_index >=m_size, the function exits.
* This function returns an error value, if returning Error, please select the most
* appropriate error condition from error_macros.h
@ -154,6 +164,16 @@ extern bool _err_error_exists;
_err_error_exists = false; \
} while (0); // (*)
#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
do { \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
ERR_EXPLAIN(m_msg); \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return m_retval; \
} \
_err_error_exists = false; \
} while (0); // (*)
/** An index has failed if m_index >=m_size, the function exits.
* This function returns an error value, if returning Error, please select the most
* appropriate error condition from error_macros.h
@ -168,6 +188,16 @@ extern bool _err_error_exists;
_err_error_exists = false; \
} while (0); // (*)
#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
do { \
if (unlikely((m_index) >= (m_size))) { \
ERR_EXPLAIN(m_msg); \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return m_retval; \
} \
_err_error_exists = false; \
} while (0); // (*)
/** Use this one if there is no sensible fallback, that is, the error is unrecoverable.
* We'll return a null reference and try to keep running.
*/
@ -179,6 +209,15 @@ extern bool _err_error_exists;
} \
} while (0); // (*)
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
do { \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
ERR_EXPLAIN(m_msg); \
_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), true); \
GENERATE_TRAP \
} \
} while (0); // (*)
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
* the function will exit.
*/
@ -192,6 +231,16 @@ extern bool _err_error_exists;
_err_error_exists = false; \
}
#define ERR_FAIL_NULL_MSG(m_param, m_msg) \
{ \
if (unlikely(!m_param)) { \
ERR_EXPLAIN(m_msg); \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null."); \
return; \
} \
_err_error_exists = false; \
}
#define ERR_FAIL_NULL_V(m_param, m_retval) \
{ \
if (unlikely(!m_param)) { \
@ -201,6 +250,16 @@ extern bool _err_error_exists;
_err_error_exists = false; \
}
#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \
{ \
if (unlikely(!m_param)) { \
ERR_EXPLAIN(m_msg); \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null."); \
return m_retval; \
} \
_err_error_exists = false; \
}
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
* the function will exit.
*/
@ -214,6 +273,16 @@ extern bool _err_error_exists;
_err_error_exists = false; \
}
#define ERR_FAIL_COND_MSG(m_cond, m_msg) \
{ \
if (unlikely(m_cond)) { \
ERR_EXPLAIN(m_msg); \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true."); \
return; \
} \
_err_error_exists = false; \
}
/** Use this one if there is no sensible fallback, that is, the error is unrecoverable.
*/
@ -225,6 +294,15 @@ extern bool _err_error_exists;
} \
}
#define CRASH_COND_MSG(m_cond, m_msg) \
{ \
if (unlikely(m_cond)) { \
ERR_EXPLAIN(m_msg); \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition ' " _STR(m_cond) " ' is true."); \
GENERATE_TRAP \
} \
}
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
* the function will exit.
* This function returns an error value, if returning Error, please select the most
@ -240,6 +318,16 @@ extern bool _err_error_exists;
_err_error_exists = false; \
}
#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \
{ \
if (unlikely(m_cond)) { \
ERR_EXPLAIN(m_msg); \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. returned: " _STR(m_retval)); \
return m_retval; \
} \
_err_error_exists = false; \
}
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
* the loop will skip to the next iteration.
*/
@ -253,6 +341,16 @@ extern bool _err_error_exists;
_err_error_exists = false; \
}
#define ERR_CONTINUE_MSG(m_cond, m_msg) \
{ \
if (unlikely(m_cond)) { \
ERR_EXPLAIN(m_msg); \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Continuing..:"); \
continue; \
} \
_err_error_exists = false; \
}
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
* the loop will break
*/
@ -266,6 +364,16 @@ extern bool _err_error_exists;
_err_error_exists = false; \
}
#define ERR_BREAK_MSG(m_cond, m_msg) \
{ \
if (unlikely(m_cond)) { \
ERR_EXPLAIN(m_msg); \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:"); \
break; \
} \
_err_error_exists = false; \
}
/** Print an error string and return
*/
@ -276,6 +384,12 @@ extern bool _err_error_exists;
return; \
}
#define ERR_FAIL_MSG(m_msg) \
{ \
ERR_EXPLAIN(m_msg); \
ERR_FAIL(); \
}
/** Print an error string and return with value
*/
@ -286,6 +400,12 @@ extern bool _err_error_exists;
return m_value; \
}
#define ERR_FAIL_V_MSG(m_value, m_msg) \
{ \
ERR_EXPLAIN(m_msg); \
ERR_FAIL_V(m_value); \
}
/** Use this one if there is no sensible fallback, that is, the error is unrecoverable.
*/
@ -295,6 +415,12 @@ extern bool _err_error_exists;
GENERATE_TRAP \
}
#define CRASH_NOW_MSG(m_msg) \
{ \
ERR_EXPLAIN(m_msg); \
CRASH_NOW(); \
}
/** Print an error string.
*/
@ -355,4 +481,15 @@ extern bool _err_error_exists;
} \
}
#define WARN_DEPRECATED_MSG(m_msg) \
{ \
static volatile bool warning_shown = false; \
if (!warning_shown) { \
ERR_EXPLAIN(m_msg); \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future", ERR_HANDLER_WARNING); \
_err_error_exists = false; \
warning_shown = true; \
} \
}
#endif

View file

@ -46,6 +46,17 @@ Variant FuncRef::call_func(const Variant **p_args, int p_argcount, Variant::Call
return obj->call(function, p_args, p_argcount, r_error);
}
Variant FuncRef::call_funcv(const Array &p_args) {
ERR_FAIL_COND_V(id == 0, Variant());
Object *obj = ObjectDB::get_instance(id);
ERR_FAIL_COND_V(!obj, Variant());
return obj->callv(function, p_args);
}
void FuncRef::set_instance(Object *p_obj) {
ERR_FAIL_NULL(p_obj);
@ -77,6 +88,8 @@ void FuncRef::_bind_methods() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_func", &FuncRef::call_func, mi, defargs);
}
ClassDB::bind_method(D_METHOD("call_funcv", "arg_array"), &FuncRef::call_funcv);
ClassDB::bind_method(D_METHOD("set_instance", "instance"), &FuncRef::set_instance);
ClassDB::bind_method(D_METHOD("set_function", "name"), &FuncRef::set_function);
ClassDB::bind_method(D_METHOD("is_valid"), &FuncRef::is_valid);

View file

@ -44,6 +44,7 @@ protected:
public:
Variant call_func(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
Variant call_funcv(const Array &p_args);
void set_instance(Object *p_obj);
void set_function(const StringName &p_func);
bool is_valid() const;

View file

@ -151,11 +151,7 @@ private:
return;
Element **new_hash_table = memnew_arr(Element *, ((uint64_t)1 << new_hash_table_power));
if (!new_hash_table) {
ERR_PRINT("Out of Memory");
return;
}
ERR_FAIL_COND_MSG(!new_hash_table, "Out of memory.");
for (int i = 0; i < (1 << new_hash_table_power); i++) {
@ -208,10 +204,7 @@ private:
/* if element doesn't exist, create it */
Element *e = memnew(Element);
if (!e) {
ERR_EXPLAIN("Out of memory");
ERR_FAIL_V(NULL);
}
ERR_FAIL_COND_V_MSG(!e, NULL, "Out of memory.");
uint32_t hash = Hasher::hash(p_key);
uint32_t index = hash & ((1 << hash_table_power) - 1);
e->next = hash_table[index];
@ -498,10 +491,7 @@ public:
} else { /* get the next key */
const Element *e = get_element(*p_key);
if (!e) {
ERR_EXPLAIN("Invalid key supplied")
ERR_FAIL_V(NULL);
}
ERR_FAIL_COND_V_MSG(!e, NULL, "Invalid key supplied.");
if (e->next) {
/* if there is a "next" in the list, return that */
return &e->next->pair.key;

View file

@ -83,6 +83,7 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
};
SavePNGFunc Image::save_png_func = NULL;
SaveEXRFunc Image::save_exr_func = NULL;
void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel) {
@ -422,8 +423,7 @@ void Image::convert(Format p_new_format) {
if (format > FORMAT_RGBE9995 || p_new_format > FORMAT_RGBE9995) {
ERR_EXPLAIN("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
ERR_FAIL();
ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
} else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8) {
@ -753,15 +753,14 @@ static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict
for (int32_t buffer_x = 0; buffer_x < dst_width; buffer_x++) {
float src_real_x = buffer_x * x_scale;
int32_t src_x = src_real_x;
int32_t start_x = MAX(0, src_x - half_kernel + 1);
int32_t end_x = MIN(src_width - 1, src_x + half_kernel);
// The corresponding point on the source image
float src_x = (buffer_x + 0.5f) * x_scale; // Offset by 0.5 so it uses the pixel's center
int32_t start_x = MAX(0, int32_t(src_x) - half_kernel + 1);
int32_t end_x = MIN(src_width - 1, int32_t(src_x) + half_kernel);
// Create the kernel used by all the pixels of the column
for (int32_t target_x = start_x; target_x <= end_x; target_x++)
kernel[target_x - start_x] = _lanczos((src_real_x - target_x) / scale_factor);
kernel[target_x - start_x] = _lanczos((target_x + 0.5f - src_x) / scale_factor);
for (int32_t buffer_y = 0; buffer_y < src_height; buffer_y++) {
@ -804,14 +803,12 @@ static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict
for (int32_t dst_y = 0; dst_y < dst_height; dst_y++) {
float buffer_real_y = dst_y * y_scale;
int32_t buffer_y = buffer_real_y;
int32_t start_y = MAX(0, buffer_y - half_kernel + 1);
int32_t end_y = MIN(src_height - 1, buffer_y + half_kernel);
float buffer_y = (dst_y + 0.5f) * y_scale;
int32_t start_y = MAX(0, int32_t(buffer_y) - half_kernel + 1);
int32_t end_y = MIN(src_height - 1, int32_t(buffer_y) + half_kernel);
for (int32_t target_y = start_y; target_y <= end_y; target_y++)
kernel[target_y - start_y] = _lanczos((buffer_real_y - target_y) / scale_factor);
kernel[target_y - start_y] = _lanczos((target_y + 0.5f - buffer_y) / scale_factor);
for (int32_t dst_x = 0; dst_x < dst_width; dst_x++) {
@ -866,10 +863,7 @@ bool Image::is_size_po2() const {
void Image::resize_to_po2(bool p_square) {
if (!_can_modify(format)) {
ERR_EXPLAIN("Cannot resize in indexed, compressed or custom image formats.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
int w = next_power_of_2(width);
int h = next_power_of_2(height);
@ -885,15 +879,9 @@ void Image::resize_to_po2(bool p_square) {
void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
if (data.size() == 0) {
ERR_EXPLAIN("Cannot resize image before creating it, use create() or create_from_data() first.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use create() or create_from_data() first.");
if (!_can_modify(format)) {
ERR_EXPLAIN("Cannot resize in indexed, compressed or custom image formats.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
@ -1106,10 +1094,8 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) {
if (!_can_modify(format)) {
ERR_EXPLAIN("Cannot crop in indexed, compressed or custom image formats.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot crop in compressed or custom image formats.");
ERR_FAIL_COND(p_x < 0);
ERR_FAIL_COND(p_y < 0);
ERR_FAIL_COND(p_width <= 0);
@ -1163,10 +1149,7 @@ void Image::crop(int p_width, int p_height) {
void Image::flip_y() {
if (!_can_modify(format)) {
ERR_EXPLAIN("Cannot flip_y in indexed, compressed or custom image formats.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in compressed or custom image formats.");
bool used_mipmaps = has_mipmaps();
if (used_mipmaps) {
@ -1199,10 +1182,7 @@ void Image::flip_y() {
void Image::flip_x() {
if (!_can_modify(format)) {
ERR_EXPLAIN("Cannot flip_x in indexed, compressed or custom image formats.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_x in compressed or custom image formats.");
bool used_mipmaps = has_mipmaps();
if (used_mipmaps) {
@ -1461,15 +1441,9 @@ void Image::normalize() {
Error Image::generate_mipmaps(bool p_renormalize) {
if (!_can_modify(format)) {
ERR_EXPLAIN("Cannot generate mipmaps in indexed, compressed or custom image formats.");
ERR_FAIL_V(ERR_UNAVAILABLE);
}
ERR_FAIL_COND_V_MSG(!_can_modify(format), ERR_UNAVAILABLE, "Cannot generate mipmaps in compressed or custom image formats.");
if (width == 0 || height == 0) {
ERR_EXPLAIN("Cannot generate mipmaps with width or height equal to 0.");
ERR_FAIL_V(ERR_UNCONFIGURED);
}
ERR_FAIL_COND_V_MSG(width == 0 || height == 0, ERR_UNCONFIGURED, "Cannot generate mipmaps with width or height equal to 0.");
int mmcount;
@ -1620,10 +1594,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
int mm;
int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
if (size != p_data.size()) {
ERR_EXPLAIN("Expected data size of " + itos(size) + " bytes in Image::create(), got instead " + itos(p_data.size()) + " bytes.");
ERR_FAIL_COND(p_data.size() != size);
}
ERR_FAIL_COND_MSG(p_data.size() != size, "Expected data size of " + itos(size) + " bytes in Image::create(), got instead " + itos(p_data.size()) + " bytes.");
height = p_height;
width = p_width;
@ -1917,6 +1888,14 @@ Error Image::save_png(const String &p_path) const {
return save_png_func(p_path, Ref<Image>((Image *)this));
}
Error Image::save_exr(const String &p_path, bool p_grayscale) const {
if (save_exr_func == NULL)
return ERR_UNAVAILABLE;
return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale);
}
int Image::get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps) {
int mm;
@ -2405,10 +2384,7 @@ Color Image::get_pixel(int p_x, int p_y) const {
uint8_t *ptr = write_lock.ptr();
#ifdef DEBUG_ENABLED
if (!ptr) {
ERR_EXPLAIN("Image must be locked with 'lock()' before using get_pixel()");
ERR_FAIL_V(Color());
}
ERR_FAIL_COND_V_MSG(!ptr, Color(), "Image must be locked with 'lock()' before using get_pixel().");
ERR_FAIL_INDEX_V(p_x, width, Color());
ERR_FAIL_INDEX_V(p_y, height, Color());
@ -2524,8 +2500,7 @@ Color Image::get_pixel(int p_x, int p_y) const {
return Color::from_rgbe9995(((uint32_t *)ptr)[ofs]);
}
default: {
ERR_EXPLAIN("Can't get_pixel() on compressed image, sorry.");
ERR_FAIL_V(Color());
ERR_FAIL_V_MSG(Color(), "Can't get_pixel() on compressed image, sorry.");
}
}
}
@ -2538,10 +2513,7 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
uint8_t *ptr = write_lock.ptr();
#ifdef DEBUG_ENABLED
if (!ptr) {
ERR_EXPLAIN("Image must be locked with 'lock()' before using set_pixel()");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(!ptr, "Image must be locked with 'lock()' before using set_pixel().");
ERR_FAIL_INDEX(p_x, width);
ERR_FAIL_INDEX(p_y, height);
@ -2653,8 +2625,7 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
} break;
default: {
ERR_EXPLAIN("Can't set_pixel() on compressed image, sorry.");
ERR_FAIL();
ERR_FAIL_MSG("Can't set_pixel() on compressed image, sorry.");
}
}
}
@ -2746,6 +2717,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("load", "path"), &Image::load);
ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png);
ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false));
ClassDB::bind_method(D_METHOD("detect_alpha"), &Image::detect_alpha);
ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible);

View file

@ -49,11 +49,14 @@ class Image;
typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img);
typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale);
class Image : public Resource {
GDCLASS(Image, Resource);
public:
static SavePNGFunc save_png_func;
static SaveEXRFunc save_exr_func;
enum {
MAX_WIDTH = 16384, // force a limit somehow
@ -217,9 +220,7 @@ public:
/**
* Resize the image, using the preferred interpolation method.
* Indexed-Color images always use INTERPOLATE_NEAREST.
*/
void resize_to_po2(bool p_square = false);
void resize(int p_width, int p_height, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
void shrink_x2();
@ -258,6 +259,7 @@ public:
Error load(const String &p_path);
Error save_png(const String &p_path) const;
Error save_exr(const String &p_path, bool p_grayscale) const;
/**
* create an empty image

View file

@ -192,10 +192,7 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName
bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_strength) const {
Map<StringName, Action>::Element *E = input_map.find(p_action);
if (!E) {
ERR_EXPLAIN("Request for nonexistent InputMap action: " + String(p_action));
ERR_FAIL_V(false);
}
ERR_FAIL_COND_V_MSG(!E, false, "Request for nonexistent InputMap action: " + String(p_action) + ".");
Ref<InputEventAction> input_event_action = p_event;
if (input_event_action.is_valid()) {

View file

@ -86,10 +86,7 @@ void ConfigFile::set_value(const String &p_section, const String &p_key, const V
Variant ConfigFile::get_value(const String &p_section, const String &p_key, Variant p_default) const {
if (!values.has(p_section) || !values[p_section].has(p_key)) {
if (p_default.get_type() == Variant::NIL) {
ERR_EXPLAIN("Couldn't find the given section/key and no default was given");
ERR_FAIL_V(p_default);
}
ERR_FAIL_COND_V_MSG(p_default.get_type() == Variant::NIL, p_default, "Couldn't find the given section/key and no default was given.");
return p_default;
}
return values[p_section][p_key];
@ -204,7 +201,7 @@ Error ConfigFile::load(const String &p_path) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
if (!f)
return ERR_CANT_OPEN;
return err;
return _internal_load(p_path, f);
}
@ -271,7 +268,7 @@ Error ConfigFile::_internal_load(const String &p_path, FileAccess *f) {
memdelete(f);
return OK;
} else if (err != OK) {
ERR_PRINTS("ConfgFile::load - " + p_path + ":" + itos(lines) + " error: " + error_text);
ERR_PRINTS("ConfgFile::load - " + p_path + ":" + itos(lines) + " error: " + error_text + ".");
memdelete(f);
return err;
}

View file

@ -87,10 +87,8 @@ bool FileAccessBuffered::eof_reached() const {
}
uint8_t FileAccessBuffered::get_8() const {
if (!file.open) {
ERR_EXPLAIN("Can't get data, when file is not opened.");
ERR_FAIL_V(0);
}
ERR_FAIL_COND_V_MSG(!file.open, 0, "Can't get data, when file is not opened.");
uint8_t byte = 0;
if (cache_data_left() >= 1) {
@ -104,10 +102,8 @@ uint8_t FileAccessBuffered::get_8() const {
}
int FileAccessBuffered::get_buffer(uint8_t *p_dest, int p_length) const {
if (!file.open) {
ERR_EXPLAIN("Can't get buffer, when file is not opened.");
ERR_FAIL_V(-1);
}
ERR_FAIL_COND_V_MSG(!file.open, -1, "Can't get buffer, when file is not opened.");
if (p_length > cache_size) {

View file

@ -40,10 +40,7 @@ class FileAccessBufferedFA : public FileAccessBuffered {
int read_data_block(int p_offset, int p_size, uint8_t *p_dest = 0) const {
if (!f.is_open()) {
ERR_EXPLAIN("Can't read data block, when file is not opened.");
ERR_FAIL_V(-1);
}
ERR_FAIL_COND_V_MSG(!f.is_open(), -1, "Can't read data block when file is not opened.");
((T *)&f)->seek(p_offset);

View file

@ -208,7 +208,8 @@ void FileAccessCompressed::seek(size_t p_position) {
if (p_position == read_total) {
at_end = true;
} else {
at_end = false;
read_eof = false;
int block_idx = p_position / block_size;
if (block_idx != read_block) {

View file

@ -30,7 +30,7 @@
#include "file_access_encrypted.h"
#include "core/math/crypto_core.h"
#include "core/crypto/crypto_core.h"
#include "core/os/copymem.h"
#include "core/print_string.h"
#include "core/variant.h"
@ -94,8 +94,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8
unsigned char hash[16];
ERR_FAIL_COND_V(CryptoCore::md5(data.ptr(), data.size(), hash) != OK, ERR_BUG);
ERR_EXPLAIN("The MD5 sum of the decrypted file does not match the expected value. It could be that the file is corrupt, or that the provided decryption key is invalid.");
ERR_FAIL_COND_V(String::md5(hash) != String::md5(md5d), ERR_FILE_CORRUPT);
ERR_FAIL_COND_V_MSG(String::md5(hash) != String::md5(md5d), ERR_FILE_CORRUPT, "The MD5 sum of the decrypted file does not match the expected value. It could be that the file is corrupt, or that the provided decryption key is invalid.");
file = p_base;
}
@ -298,7 +297,7 @@ uint32_t FileAccessEncrypted::_get_unix_permissions(const String &p_file) {
}
Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
ERR_PRINT("Setting UNIX permissions on encrypted files is not implemented yet");
ERR_PRINT("Setting UNIX permissions on encrypted files is not implemented yet.");
return ERR_UNAVAILABLE;
}

View file

@ -90,7 +90,7 @@ void PackedData::add_path(const String &pkg_path, const String &path, uint64_t o
}
}
String filename = path.get_file();
// Don't add as a file if the path points to a directoryy
// Don't add as a file if the path points to a directory
if (!filename.empty()) {
cd->files.insert(filename);
}
@ -171,10 +171,8 @@ bool PackedSourcePCK::try_open_pack(const String &p_path) {
uint32_t ver_minor = f->get_32();
f->get_32(); // ver_rev
ERR_EXPLAIN("Pack version unsupported: " + itos(version));
ERR_FAIL_COND_V(version != PACK_VERSION, false);
ERR_EXPLAIN("Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor));
ERR_FAIL_COND_V(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false);
ERR_FAIL_COND_V_MSG(version != PACK_VERSION, false, "Pack version unsupported: " + itos(version) + ".");
ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + ".");
for (int i = 0; i < 16; i++) {
//reserved
@ -322,10 +320,9 @@ bool FileAccessPack::file_exists(const String &p_name) {
FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) :
pf(p_file),
f(FileAccess::open(pf.pack, FileAccess::READ)) {
if (!f) {
ERR_EXPLAIN("Can't open pack-referenced file: " + String(pf.pack));
ERR_FAIL_COND(!f);
}
ERR_FAIL_COND_MSG(!f, "Can't open pack-referenced file: " + String(pf.pack) + ".");
f->seek(pf.offset);
pos = 0;
eof = false;
@ -463,11 +460,15 @@ String DirAccessPack::get_current_dir() {
bool DirAccessPack::file_exists(String p_file) {
p_file = fix_path(p_file);
return current->files.has(p_file);
}
bool DirAccessPack::dir_exists(String p_dir) {
p_dir = fix_path(p_dir);
return current->subdirs.has(p_dir);
}

View file

@ -37,24 +37,8 @@
#include "core/os/file_access.h"
#include "core/ustring.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
/**
* @class ImageScanLineLoader
* @author Juan Linietsky <reduzio@gmail.com>
*
*/
class ImageLoader;
/**
* @class ImageLoader
* Base Class and singleton for loading images from disk
* Can load images in one go, or by scanline
*/
class ImageFormatLoader {
friend class ImageLoader;
friend class ResourceFormatLoaderImage;

View file

@ -81,8 +81,7 @@ static void _parse_hex(const String &p_string, int p_start, uint8_t *p_dst) {
} else if (c == ':') {
break;
} else {
ERR_EXPLAIN("Invalid character in ipv6 address: " + p_string);
ERR_FAIL();
ERR_FAIL_MSG("Invalid character in IPv6 address: " + p_string + ".");
};
ret = ret << 4;
ret += n;
@ -126,9 +125,7 @@ void IP_Address::_parse_ipv6(const String &p_string) {
++parts_count;
};
} else {
ERR_EXPLAIN("Invalid character in IPv6 address: " + p_string);
ERR_FAIL();
ERR_FAIL_MSG("Invalid character in IPv6 address: " + p_string + ".");
};
};
@ -166,10 +163,7 @@ void IP_Address::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret
};
int slices = ip.get_slice_count(".");
if (slices != 4) {
ERR_EXPLAIN("Invalid IP Address String: " + ip);
ERR_FAIL();
}
ERR_FAIL_COND_MSG(slices != 4, "Invalid IP address string: " + ip + ".");
for (int i = 0; i < 4; i++) {
p_ret[i] = ip.get_slicec('.', i).to_int();
}
@ -229,7 +223,7 @@ IP_Address::IP_Address(const String &p_string) {
valid = true;
} else {
ERR_PRINT("Invalid IP address");
ERR_PRINT("Invalid IP address.");
}
}

View file

@ -377,11 +377,6 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
}
} break;
/*case Variant::RESOURCE: {
ERR_EXPLAIN("Can't marshallize resources");
ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go
} break;*/
case Variant::_RID: {
r_variant = RID();
@ -1066,11 +1061,6 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len += 4 * 4;
} break;
/*case Variant::RESOURCE: {
ERR_EXPLAIN("Can't marshallize resources");
ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go
} break;*/
case Variant::_RID: {
} break;

View file

@ -33,6 +33,10 @@
#include "core/io/marshalls.h"
#include "scene/main/node.h"
#ifdef DEBUG_ENABLED
#include "core/os/os.h"
#endif
_FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_master, bool &r_skip_rpc) {
switch (mode) {
@ -146,8 +150,7 @@ void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_pee
network_peer = p_peer;
ERR_EXPLAIN("Supplied NetworkedNetworkPeer must be connecting or connected.");
ERR_FAIL_COND(p_peer.is_valid() && p_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED);
ERR_FAIL_COND_MSG(p_peer.is_valid() && p_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, "Supplied NetworkedNetworkPeer must be connecting or connected.");
if (network_peer.is_valid()) {
network_peer->connect("peer_connected", this, "_add_peer");
@ -164,10 +167,16 @@ Ref<NetworkedMultiplayerPeer> MultiplayerAPI::get_network_peer() const {
void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) {
ERR_EXPLAIN("Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it");
ERR_FAIL_COND(root_node == NULL);
ERR_EXPLAIN("Invalid packet received. Size too small.");
ERR_FAIL_COND(p_packet_len < 1);
ERR_FAIL_COND_MSG(root_node == NULL, "Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it.");
ERR_FAIL_COND_MSG(p_packet_len < 1, "Invalid packet received. Size too small.");
#ifdef DEBUG_ENABLED
if (profiling) {
bandwidth_incoming_data.write[bandwidth_incoming_pointer].timestamp = OS::get_singleton()->get_ticks_msec();
bandwidth_incoming_data.write[bandwidth_incoming_pointer].packet_size = p_packet_len;
bandwidth_incoming_pointer = (bandwidth_incoming_pointer + 1) % bandwidth_incoming_data.size();
}
#endif
uint8_t packet_type = p_packet[0];
@ -186,13 +195,11 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
case NETWORK_COMMAND_REMOTE_CALL:
case NETWORK_COMMAND_REMOTE_SET: {
ERR_EXPLAIN("Invalid packet received. Size too small.");
ERR_FAIL_COND(p_packet_len < 6);
ERR_FAIL_COND_MSG(p_packet_len < 6, "Invalid packet received. Size too small.");
Node *node = _process_get_node(p_from, p_packet, p_packet_len);
ERR_EXPLAIN("Invalid packet received. Requested node was not found.");
ERR_FAIL_COND(node == NULL);
ERR_FAIL_COND_MSG(node == NULL, "Invalid packet received. Requested node was not found.");
// Detect cstring end.
int len_end = 5;
@ -202,8 +209,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
}
}
ERR_EXPLAIN("Invalid packet received. Size too small.");
ERR_FAIL_COND(len_end >= p_packet_len);
ERR_FAIL_COND_MSG(len_end >= p_packet_len, "Invalid packet received. Size too small.");
StringName name = String::utf8((const char *)&p_packet[5]);
@ -235,8 +241,7 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int
int ofs = target & 0x7FFFFFFF;
ERR_EXPLAIN("Invalid packet received. Size smaller than declared.");
ERR_FAIL_COND_V(ofs >= p_packet_len, NULL);
ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, NULL, "Invalid packet received. Size smaller than declared.");
String paths;
paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs);
@ -246,33 +251,30 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int
node = root_node->get_node(np);
if (!node)
ERR_PRINTS("Failed to get path from RPC: " + String(np));
ERR_PRINTS("Failed to get path from RPC: " + String(np) + ".");
} else {
// Use cached path.
int id = target;
Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from);
ERR_EXPLAIN("Invalid packet received. Requests invalid peer cache.");
ERR_FAIL_COND_V(!E, NULL);
ERR_FAIL_COND_V_MSG(!E, NULL, "Invalid packet received. Requests invalid peer cache.");
Map<int, PathGetCache::NodeInfo>::Element *F = E->get().nodes.find(id);
ERR_EXPLAIN("Invalid packet received. Unabled to find requested cached node.");
ERR_FAIL_COND_V(!F, NULL);
ERR_FAIL_COND_V_MSG(!F, NULL, "Invalid packet received. Unabled to find requested cached node.");
PathGetCache::NodeInfo *ni = &F->get();
// Do proper caching later.
node = root_node->get_node(ni->path);
if (!node)
ERR_PRINTS("Failed to get cached path from RPC: " + String(ni->path));
ERR_PRINTS("Failed to get cached path from RPC: " + String(ni->path) + ".");
}
return node;
}
void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
ERR_EXPLAIN("Invalid packet received. Size too small.");
ERR_FAIL_COND(p_offset >= p_packet_len);
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
// Check that remote can call the RPC on this node.
RPCMode rpc_mode = RPC_MODE_DISABLED;
@ -284,8 +286,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
}
bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
ERR_FAIL_COND(!can_call);
ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
int argc = p_packet[p_offset];
Vector<Variant> args;
@ -295,15 +296,21 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
p_offset++;
#ifdef DEBUG_ENABLED
if (profiling) {
ObjectID id = p_node->get_instance_id();
_init_node_profile(id);
profiler_frame_data[id].incoming_rpc += 1;
}
#endif
for (int i = 0; i < argc; i++) {
ERR_EXPLAIN("Invalid packet received. Size too small.");
ERR_FAIL_COND(p_offset >= p_packet_len);
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
int vlen;
Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Invalid packet received. Unable to decode RPC argument.");
ERR_FAIL_COND(err != OK);
ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RPC argument.");
argp.write[i] = &args[i];
p_offset += vlen;
@ -321,8 +328,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
ERR_EXPLAIN("Invalid packet received. Size too small.");
ERR_FAIL_COND(p_offset >= p_packet_len);
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
// Check that remote can call the RSET on this node.
RPCMode rset_mode = RPC_MODE_DISABLED;
@ -334,28 +340,33 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p
}
bool can_call = _can_call_mode(p_node, rset_mode, p_from);
ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
ERR_FAIL_COND(!can_call);
ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
#ifdef DEBUG_ENABLED
if (profiling) {
ObjectID id = p_node->get_instance_id();
_init_node_profile(id);
profiler_frame_data[id].incoming_rset += 1;
}
#endif
Variant value;
Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Invalid packet received. Unable to decode RSET value.");
ERR_FAIL_COND(err != OK);
ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value.");
bool valid;
p_node->set(p_name, value, &valid);
if (!valid) {
String error = "Error setting remote property '" + String(p_name) + "', not found in object of type " + p_node->get_class();
String error = "Error setting remote property '" + String(p_name) + "', not found in object of type " + p_node->get_class() + ".";
ERR_PRINTS(error);
}
}
void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
ERR_EXPLAIN("Invalid packet received. Size too small.");
ERR_FAIL_COND(p_packet_len < 5);
ERR_FAIL_COND_MSG(p_packet_len < 5, "Invalid packet received. Size too small.");
int id = decode_uint32(&p_packet[1]);
String paths;
@ -390,8 +401,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
ERR_EXPLAIN("Invalid packet received. Size too small.");
ERR_FAIL_COND(p_packet_len < 2);
ERR_FAIL_COND_MSG(p_packet_len < 2, "Invalid packet received. Size too small.");
String paths;
paths.parse_utf8((const char *)&p_packet[1], p_packet_len - 1);
@ -399,12 +409,10 @@ void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet,
NodePath path = paths;
PathSentCache *psc = path_send_cache.getptr(path);
ERR_EXPLAIN("Invalid packet received. Tries to confirm a path which was not found in cache.");
ERR_FAIL_COND(!psc);
ERR_FAIL_COND_MSG(!psc, "Invalid packet received. Tries to confirm a path which was not found in cache.");
Map<int, bool>::Element *E = psc->confirmed_peers.find(p_from);
ERR_EXPLAIN("Invalid packet received. Source peer was not found in cache for the given path.");
ERR_FAIL_COND(!E);
ERR_FAIL_COND_MSG(!E, "Invalid packet received. Source peer was not found in cache for the given path.");
E->get() = true;
}
@ -460,39 +468,22 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int
void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) {
if (network_peer.is_null()) {
ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree.");
if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING) {
ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree.");
if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) {
ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected.");
if (p_argcount > 255) {
ERR_EXPLAIN("Too many arguments >255.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(p_argcount > 255, "Too many arguments >255.");
if (p_to != 0 && !connected_peers.has(ABS(p_to))) {
if (p_to == network_peer->get_unique_id()) {
ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: " + itos(network_peer->get_unique_id()));
} else {
ERR_EXPLAIN("Attempt to remote call unexisting ID: " + itos(p_to));
}
ERR_FAIL_COND_MSG(p_to == network_peer->get_unique_id(), "Attempt to remote call/set yourself! unique ID: " + itos(network_peer->get_unique_id()) + ".");
ERR_FAIL();
ERR_FAIL_MSG("Attempt to remote call unexisting ID: " + itos(p_to) + ".");
}
NodePath from_path = (root_node->get_path()).rel_path_to(p_from->get_path());
ERR_EXPLAIN("Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!");
ERR_FAIL_COND(from_path.is_empty());
ERR_FAIL_COND_MSG(from_path.is_empty(), "Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!");
// See if the path is cached.
PathSentCache *psc = path_send_cache.getptr(from_path);
@ -530,8 +521,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
if (p_set) {
// Set argument.
Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!");
ERR_FAIL_COND(err != OK);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ofs += len;
@ -543,14 +533,21 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
ofs += 1;
for (int i = 0; i < p_argcount; i++) {
Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
ERR_FAIL_COND(err != OK);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ofs += len;
}
}
#ifdef DEBUG_ENABLED
if (profiling) {
bandwidth_outgoing_data.write[bandwidth_outgoing_pointer].timestamp = OS::get_singleton()->get_ticks_msec();
bandwidth_outgoing_data.write[bandwidth_outgoing_pointer].packet_size = ofs;
bandwidth_outgoing_pointer = (bandwidth_outgoing_pointer + 1) % bandwidth_outgoing_data.size();
}
#endif
// See if all peers have cached path (is so, call can be fast).
bool has_all_peers = _send_confirm_path(from_path, psc, p_to);
@ -626,12 +623,9 @@ void MultiplayerAPI::_server_disconnected() {
void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) {
ERR_EXPLAIN("Trying to call an RPC while no network peer is active.");
ERR_FAIL_COND(!network_peer.is_valid());
ERR_EXPLAIN("Trying to call an RPC on a node which is not inside SceneTree.");
ERR_FAIL_COND(!p_node->is_inside_tree());
ERR_EXPLAIN("Trying to call an RPC via a network peer which is not connected.");
ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED);
ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to call an RPC while no network peer is active.");
ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to call an RPC on a node which is not inside SceneTree.");
ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected.");
int node_id = network_peer->get_unique_id();
bool skip_rpc = node_id == p_peer_id;
@ -657,6 +651,15 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
if (!skip_rpc) {
#ifdef DEBUG_ENABLED
if (profiling) {
ObjectID id = p_node->get_instance_id();
_init_node_profile(id);
profiler_frame_data[id].outgoing_rpc += 1;
}
#endif
_send_rpc(p_node, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount);
}
@ -668,7 +671,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
rpc_sender_id = temp_id;
if (ce.error != Variant::CallError::CALL_OK) {
String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce);
error = "rpc() aborted in local call: - " + error;
error = "rpc() aborted in local call: - " + error + ".";
ERR_PRINTS(error);
return;
}
@ -683,24 +686,20 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
rpc_sender_id = temp_id;
if (ce.error != Variant::CallError::CALL_OK) {
String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce);
error = "rpc() aborted in script local call: - " + error;
error = "rpc() aborted in script local call: - " + error + ".";
ERR_PRINTS(error);
return;
}
}
ERR_EXPLAIN("RPC '" + p_method + "' on yourself is not allowed by selected mode");
ERR_FAIL_COND(skip_rpc && !(call_local_native || call_local_script));
ERR_FAIL_COND_MSG(skip_rpc && !(call_local_native || call_local_script), "RPC '" + p_method + "' on yourself is not allowed by selected mode.");
}
void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
ERR_EXPLAIN("Trying to RSET while no network peer is active.");
ERR_FAIL_COND(!network_peer.is_valid());
ERR_EXPLAIN("Trying to RSET on a node which is not inside SceneTree.");
ERR_FAIL_COND(!p_node->is_inside_tree());
ERR_EXPLAIN("Trying to send an RSET via a network peer which is not connected.");
ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED);
ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to RSET while no network peer is active.");
ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to RSET on a node which is not inside SceneTree.");
ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to send an RSET via a network peer which is not connected.");
int node_id = network_peer->get_unique_id();
bool is_master = p_node->is_network_master();
@ -724,7 +723,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
rpc_sender_id = temp_id;
if (!valid) {
String error = "rset() aborted in local set, property not found: - " + String(p_property);
String error = "rset() aborted in local set, property not found: - " + String(p_property) + ".";
ERR_PRINTS(error);
return;
}
@ -742,7 +741,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
rpc_sender_id = temp_id;
if (!valid) {
String error = "rset() aborted in local script set, property not found: - " + String(p_property);
String error = "rset() aborted in local script set, property not found: - " + String(p_property) + ".";
ERR_PRINTS(error);
return;
}
@ -751,11 +750,18 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
if (skip_rset) {
ERR_EXPLAIN("RSET for '" + p_property + "' on yourself is not allowed by selected mode");
ERR_FAIL_COND(!set_local);
ERR_FAIL_COND_MSG(!set_local, "RSET for '" + p_property + "' on yourself is not allowed by selected mode.");
return;
}
#ifdef DEBUG_ENABLED
if (profiling) {
ObjectID id = p_node->get_instance_id();
_init_node_profile(id);
profiler_frame_data[id].outgoing_rset += 1;
}
#endif
const Variant *vptr = &p_value;
_send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1);
@ -763,12 +769,9 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) {
ERR_EXPLAIN("Trying to send an empty raw packet.");
ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_DATA);
ERR_EXPLAIN("Trying to send a raw packet while no network peer is active.");
ERR_FAIL_COND_V(!network_peer.is_valid(), ERR_UNCONFIGURED);
ERR_EXPLAIN("Trying to send a raw packet via a network peer which is not connected.");
ERR_FAIL_COND_V(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(p_data.size() < 1, ERR_INVALID_DATA, "Trying to send an empty raw packet.");
ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), ERR_UNCONFIGURED, "Trying to send a raw packet while no network peer is active.");
ERR_FAIL_COND_V_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a network peer which is not connected.");
MAKE_ROOM(p_data.size() + 1);
PoolVector<uint8_t>::Read r = p_data.read();
@ -783,8 +786,7 @@ Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, Networked
void MultiplayerAPI::_process_raw(int p_from, const uint8_t *p_packet, int p_packet_len) {
ERR_EXPLAIN("Invalid packet received. Size too small.");
ERR_FAIL_COND(p_packet_len < 2);
ERR_FAIL_COND_MSG(p_packet_len < 2, "Invalid packet received. Size too small.");
PoolVector<uint8_t> out;
int len = p_packet_len - 1;
@ -798,37 +800,32 @@ void MultiplayerAPI::_process_raw(int p_from, const uint8_t *p_packet, int p_pac
int MultiplayerAPI::get_network_unique_id() const {
ERR_EXPLAIN("No network peer is assigned. Unable to get unique network ID.");
ERR_FAIL_COND_V(!network_peer.is_valid(), 0);
ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), 0, "No network peer is assigned. Unable to get unique network ID.");
return network_peer->get_unique_id();
}
bool MultiplayerAPI::is_network_server() const {
// XXX Maybe fail silently? Maybe should actually return true to make development of both local and online multiplayer easier?
ERR_EXPLAIN("No network peer is assigned. I can't be a server.");
ERR_FAIL_COND_V(!network_peer.is_valid(), false);
ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), false, "No network peer is assigned. I can't be a server.");
return network_peer->is_server();
}
void MultiplayerAPI::set_refuse_new_network_connections(bool p_refuse) {
ERR_EXPLAIN("No network peer is assigned. Unable to set 'refuse_new_connections'.");
ERR_FAIL_COND(!network_peer.is_valid());
ERR_FAIL_COND_MSG(!network_peer.is_valid(), "No network peer is assigned. Unable to set 'refuse_new_connections'.");
network_peer->set_refuse_new_connections(p_refuse);
}
bool MultiplayerAPI::is_refusing_new_network_connections() const {
ERR_EXPLAIN("No network peer is assigned. Unable to get 'refuse_new_connections'.");
ERR_FAIL_COND_V(!network_peer.is_valid(), false);
ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), false, "No network peer is assigned. Unable to get 'refuse_new_connections'.");
return network_peer->is_refusing_new_connections();
}
Vector<int> MultiplayerAPI::get_network_connected_peers() const {
ERR_EXPLAIN("No network peer is assigned. Assume no peers are connected.");
ERR_FAIL_COND_V(!network_peer.is_valid(), Vector<int>());
ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), Vector<int>(), "No network peer is assigned. Assume no peers are connected.");
Vector<int> ret;
for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) {
@ -848,6 +845,96 @@ bool MultiplayerAPI::is_object_decoding_allowed() const {
return allow_object_decoding;
}
void MultiplayerAPI::profiling_start() {
#ifdef DEBUG_ENABLED
profiling = true;
profiler_frame_data.clear();
bandwidth_incoming_pointer = 0;
bandwidth_incoming_data.resize(16384); // ~128kB
for (int i = 0; i < bandwidth_incoming_data.size(); ++i) {
bandwidth_incoming_data.write[i].packet_size = -1;
}
bandwidth_outgoing_pointer = 0;
bandwidth_outgoing_data.resize(16384); // ~128kB
for (int i = 0; i < bandwidth_outgoing_data.size(); ++i) {
bandwidth_outgoing_data.write[i].packet_size = -1;
}
#endif
}
void MultiplayerAPI::profiling_end() {
#ifdef DEBUG_ENABLED
profiling = false;
bandwidth_incoming_data.clear();
bandwidth_outgoing_data.clear();
#endif
}
int MultiplayerAPI::get_profiling_frame(ProfilingInfo *r_info) {
int i = 0;
#ifdef DEBUG_ENABLED
for (Map<ObjectID, ProfilingInfo>::Element *E = profiler_frame_data.front(); E; E = E->next()) {
r_info[i] = E->get();
++i;
}
profiler_frame_data.clear();
#endif
return i;
}
int MultiplayerAPI::get_incoming_bandwidth_usage() {
#ifdef DEBUG_ENABLED
return _get_bandwidth_usage(bandwidth_incoming_data, bandwidth_incoming_pointer);
#else
return 0;
#endif
}
int MultiplayerAPI::get_outgoing_bandwidth_usage() {
#ifdef DEBUG_ENABLED
return _get_bandwidth_usage(bandwidth_outgoing_data, bandwidth_outgoing_pointer);
#else
return 0;
#endif
}
#ifdef DEBUG_ENABLED
int MultiplayerAPI::_get_bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer) {
int total_bandwidth = 0;
uint32_t timestamp = OS::get_singleton()->get_ticks_msec();
uint32_t final_timestamp = timestamp - 1000;
int i = (p_pointer + p_buffer.size() - 1) % p_buffer.size();
while (i != p_pointer && p_buffer[i].packet_size > 0) {
if (p_buffer[i].timestamp < final_timestamp) {
return total_bandwidth;
}
total_bandwidth += p_buffer[i].packet_size;
i = (i + p_buffer.size() - 1) % p_buffer.size();
}
ERR_EXPLAIN("Reached the end of the bandwidth profiler buffer, values might be inaccurate.");
ERR_FAIL_COND_V(i == p_pointer, total_bandwidth);
return total_bandwidth;
}
void MultiplayerAPI::_init_node_profile(ObjectID p_node) {
if (profiler_frame_data.has(p_node))
return;
profiler_frame_data.insert(p_node, ProfilingInfo());
profiler_frame_data[p_node].node = p_node;
profiler_frame_data[p_node].node_path = Object::cast_to<Node>(ObjectDB::get_instance(p_node))->get_path();
profiler_frame_data[p_node].incoming_rpc = 0;
profiler_frame_data[p_node].incoming_rset = 0;
profiler_frame_data[p_node].outgoing_rpc = 0;
profiler_frame_data[p_node].outgoing_rset = 0;
}
#endif
void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
@ -898,6 +985,9 @@ MultiplayerAPI::MultiplayerAPI() :
allow_object_decoding(false) {
rpc_sender_id = 0;
root_node = NULL;
#ifdef DEBUG_ENABLED
profiling = false;
#endif
clear();
}

View file

@ -38,6 +38,16 @@ class MultiplayerAPI : public Reference {
GDCLASS(MultiplayerAPI, Reference);
public:
struct ProfilingInfo {
ObjectID node;
String node_path;
int incoming_rpc;
int incoming_rset;
int outgoing_rpc;
int outgoing_rset;
};
private:
//path sent caches
struct PathSentCache {
@ -55,6 +65,23 @@ private:
Map<int, NodeInfo> nodes;
};
#ifdef DEBUG_ENABLED
struct BandwidthFrame {
uint32_t timestamp;
int packet_size;
};
int bandwidth_incoming_pointer;
Vector<BandwidthFrame> bandwidth_incoming_data;
int bandwidth_outgoing_pointer;
Vector<BandwidthFrame> bandwidth_outgoing_data;
Map<ObjectID, ProfilingInfo> profiler_frame_data;
bool profiling;
void _init_node_profile(ObjectID p_node);
int _get_bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer);
#endif
Ref<NetworkedMultiplayerPeer> network_peer;
int rpc_sender_id;
Set<int> connected_peers;
@ -130,6 +157,13 @@ public:
void set_allow_object_decoding(bool p_enable);
bool is_object_decoding_allowed() const;
void profiling_start();
void profiling_end();
int get_profiling_frame(ProfilingInfo *r_info);
int get_incoming_bandwidth_usage();
int get_outgoing_bandwidth_usage();
MultiplayerAPI();
~MultiplayerAPI();
};

View file

@ -110,10 +110,11 @@ Error PacketPeer::put_var(const Variant &p_packet, bool p_full_objects) {
Variant PacketPeer::_bnd_get_var(bool p_allow_objects) {
Variant var;
get_var(var, p_allow_objects);
Error err = get_var(var, p_allow_objects);
ERR_FAIL_COND_V(err != OK, Variant());
return var;
};
}
Error PacketPeer::_put_packet(const PoolVector<uint8_t> &p_buffer) {
return put_packet_buffer(p_buffer);
@ -279,8 +280,7 @@ Ref<StreamPeer> PacketPeerStream::get_stream_peer() const {
void PacketPeerStream::set_input_buffer_max_size(int p_max_size) {
//warning may lose packets
ERR_EXPLAIN("Buffer in use, resizing would cause loss of data");
ERR_FAIL_COND(ring_buffer.data_left());
ERR_FAIL_COND_MSG(ring_buffer.data_left(), "Buffer in use, resizing would cause loss of data.");
ring_buffer.resize(nearest_shift(p_max_size + 4));
input_buffer.resize(next_power_of_2(p_max_size + 4));
}

View file

@ -64,10 +64,7 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment) {
file = FileAccess::open(p_file, FileAccess::WRITE);
if (!file) {
ERR_EXPLAIN("Can't open file to write: " + String(p_file));
ERR_FAIL_V(ERR_CANT_CREATE);
}
ERR_FAIL_COND_V_MSG(!file, ERR_CANT_CREATE, "Can't open file to write: " + String(p_file) + ".");
alignment = p_alignment;

View file

@ -490,8 +490,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) {
#endif
} else {
ERR_EXPLAIN("Vector2 size is NOT 8!");
ERR_FAIL_V(ERR_UNAVAILABLE);
ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Vector2 size is NOT 8!");
}
w.release();
r_v = array;
@ -518,8 +517,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) {
#endif
} else {
ERR_EXPLAIN("Vector3 size is NOT 12!");
ERR_FAIL_V(ERR_UNAVAILABLE);
ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Vector3 size is NOT 12!");
}
w.release();
r_v = array;
@ -546,8 +544,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) {
#endif
} else {
ERR_EXPLAIN("Color size is NOT 16!");
ERR_FAIL_V(ERR_UNAVAILABLE);
ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Color size is NOT 16!");
}
w.release();
r_v = array;
@ -571,7 +568,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) {
const uint32_t current_version = 0;
if (format_version > current_version) {
ERR_PRINT("Format version for encoded binary image is too new");
ERR_PRINT("Format version for encoded binary image is too new.");
return ERR_PARSE_ERROR;
}
@ -655,8 +652,7 @@ Error ResourceInteractiveLoaderBinary::poll() {
} else {
error = ERR_FILE_MISSING_DEPENDENCIES;
ERR_EXPLAIN("Can't load dependency: " + path);
ERR_FAIL_V(error);
ERR_FAIL_V_MSG(error, "Can't load dependency: " + path + ".");
}
} else {
@ -711,16 +707,15 @@ Error ResourceInteractiveLoaderBinary::poll() {
Object *obj = ClassDB::instance(t);
if (!obj) {
error = ERR_FILE_CORRUPT;
ERR_EXPLAIN(local_path + ":Resource of unrecognized type in file: " + t);
ERR_FAIL_V(ERR_FILE_CORRUPT);
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
}
Resource *r = Object::cast_to<Resource>(obj);
if (!r) {
String obj_class = obj->get_class();
error = ERR_FILE_CORRUPT;
memdelete(obj); //bye
ERR_EXPLAIN(local_path + ":Resource type in resource field not a resource, type is: " + obj->get_class());
ERR_FAIL_V(ERR_FILE_CORRUPT);
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
}
RES res = RES(r);
@ -850,8 +845,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
//not normal
error = ERR_FILE_UNRECOGNIZED;
ERR_EXPLAIN("Unrecognized binary resource file: " + local_path);
ERR_FAIL();
ERR_FAIL_MSG("Unrecognized binary resource file: " + local_path + ".");
}
bool big_endian = f->get_32();
@ -877,8 +871,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
f->close();
ERR_EXPLAIN("File Format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path);
ERR_FAIL();
ERR_FAIL_MSG("File format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path + ".");
}
type = get_unicode_string();
@ -926,8 +919,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
if (f->eof_reached()) {
error = ERR_FILE_CORRUPT;
ERR_EXPLAIN("Premature End Of File: " + local_path);
ERR_FAIL();
ERR_FAIL_MSG("Premature end of file (EOF): " + local_path + ".");
}
}
@ -1084,8 +1076,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
//error=ERR_FILE_UNRECOGNIZED;
memdelete(f);
ERR_EXPLAIN("Unrecognized binary resource file: " + local_path);
ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unrecognized binary resource file: " + local_path + ".");
} else {
fw = FileAccess::open(p_path + ".depren", FileAccess::WRITE);
if (!fw) {
@ -1122,7 +1113,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
memdelete(da);
//use the old approach
WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: " + p_path).utf8().get_data());
WARN_PRINTS("This file is old, so it can't refactor dependencies, opening and resaving: " + p_path + ".");
Error err;
f = FileAccess::open(p_path, FileAccess::READ, &err);
@ -1153,8 +1144,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
memdelete(f);
memdelete(fw);
ERR_EXPLAIN("File Format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path);
ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "File format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path + ".");
}
// Since we're not actually converting the file contents, leave the version
@ -1477,7 +1467,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
case Variant::_RID: {
f->store_32(VARIANT_RID);
WARN_PRINT("Can't save RIDs");
WARN_PRINT("Can't save RIDs.");
RID val = p_property;
f->store_32(val.get_id());
} break;
@ -1497,8 +1487,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
if (!resource_set.has(res)) {
f->store_32(OBJECT_EMPTY);
ERR_EXPLAIN("Resource was not pre cached for the resource section, most likely due to circular refedence.");
ERR_FAIL();
ERR_FAIL_MSG("Resource was not pre cached for the resource section, most likely due to circular reference.");
}
f->store_32(OBJECT_INTERNAL_RESOURCE);
@ -1629,8 +1618,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
} break;
default: {
ERR_EXPLAIN("Invalid variant");
ERR_FAIL();
ERR_FAIL_MSG("Invalid variant.");
}
}
}
@ -1798,6 +1786,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) {
f->close();
memdelete(f);
return ERR_CANT_CREATE;
}
@ -1950,10 +1939,12 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) {
f->close();
memdelete(f);
return ERR_CANT_CREATE;
}
f->close();
memdelete(f);
return OK;
}

View file

@ -275,12 +275,9 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
return res;
}
if (found) {
ERR_EXPLAIN("Failed loading resource: " + p_path);
} else {
ERR_EXPLAIN("No loader found for resource: " + p_path);
}
ERR_FAIL_V(RES());
ERR_FAIL_COND_V_MSG(found, RES(), "Failed loading resource: " + p_path + ".");
ERR_FAIL_V_MSG(RES(), "No loader found for resource: " + p_path + ".");
}
bool ResourceLoader::_add_to_loading_map(const String &p_path) {
@ -355,10 +352,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
{
bool success = _add_to_loading_map(local_path);
if (!success) {
ERR_EXPLAIN("Resource: '" + local_path + "' is already being loaded. Cyclic reference?");
ERR_FAIL_V(RES());
}
ERR_FAIL_COND_V_MSG(!success, RES(), "Resource: '" + local_path + "' is already being loaded. Cyclic reference?");
}
//lock first if possible
@ -395,8 +389,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
if (!p_no_cache) {
_remove_from_loading_map(local_path);
}
ERR_EXPLAIN("Remapping '" + local_path + "'failed.");
ERR_FAIL_V(RES());
ERR_FAIL_V_MSG(RES(), "Remapping '" + local_path + "' failed.");
}
print_verbose("Loading resource: " + path);
@ -479,10 +472,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
if (!p_no_cache) {
bool success = _add_to_loading_map(local_path);
if (!success) {
ERR_EXPLAIN("Resource: '" + local_path + "' is already being loaded. Cyclic reference?");
ERR_FAIL_V(RES());
}
ERR_FAIL_COND_V_MSG(!success, RES(), "Resource: '" + local_path + "' is already being loaded. Cyclic reference?");
if (ResourceCache::has(local_path)) {
@ -503,8 +493,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
if (!p_no_cache) {
_remove_from_loading_map(local_path);
}
ERR_EXPLAIN("Remapping '" + local_path + "'failed.");
ERR_FAIL_V(RES());
ERR_FAIL_V_MSG(RES(), "Remapping '" + local_path + "' failed.");
}
print_verbose("Loading resource: " + path);
@ -534,12 +523,9 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
_remove_from_loading_map(local_path);
}
if (found) {
ERR_EXPLAIN("Failed loading resource: " + path);
} else {
ERR_EXPLAIN("No loader found for resource: " + path);
}
ERR_FAIL_V(Ref<ResourceInteractiveLoader>());
ERR_FAIL_COND_V_MSG(found, Ref<ResourceInteractiveLoader>(), "Failed loading resource: " + path + ".");
ERR_FAIL_V_MSG(Ref<ResourceInteractiveLoader>(), "No loader found for resource: " + path + ".");
}
void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) {
@ -801,7 +787,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
if (err == ERR_FILE_EOF) {
break;
} else if (err != OK) {
ERR_PRINTS("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text);
ERR_PRINTS("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text + ".");
break;
}
@ -932,16 +918,13 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) {
Ref<Script> s = res;
StringName ibt = s->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatLoader");
ERR_EXPLAIN("Script does not inherit a CustomResourceLoader: " + script_path);
ERR_FAIL_COND_V(!valid_type, false);
ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceLoader: " + script_path + ".");
Object *obj = ClassDB::instance(ibt);
ERR_EXPLAIN("Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt));
ERR_FAIL_COND_V(obj == NULL, false);
ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + ".");
ResourceFormatLoader *crl = NULL;
crl = Object::cast_to<ResourceFormatLoader>(obj);
ResourceFormatLoader *crl = Object::cast_to<ResourceFormatLoader>(obj);
crl->set_script(s.get_ref_ptr());
ResourceLoader::add_resource_format_loader(crl);

View file

@ -33,9 +33,6 @@
#include "core/os/thread.h"
#include "core/resource.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class ResourceInteractiveLoader : public Reference {

View file

@ -214,16 +214,13 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
Ref<Script> s = res;
StringName ibt = s->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver");
ERR_EXPLAIN("Script does not inherit a CustomResourceSaver: " + script_path);
ERR_FAIL_COND_V(!valid_type, false);
ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceSaver: " + script_path + ".");
Object *obj = ClassDB::instance(ibt);
ERR_EXPLAIN("Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt));
ERR_FAIL_COND_V(obj == NULL, false);
ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");
ResourceFormatSaver *crl = NULL;
crl = Object::cast_to<ResourceFormatSaver>(obj);
ResourceFormatSaver *crl = Object::cast_to<ResourceFormatSaver>(obj);
crl->set_script(s.get_ref_ptr());
ResourceSaver::add_resource_format_saver(crl);

View file

@ -33,10 +33,6 @@
#include "core/resource.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class ResourceFormatSaver : public Reference {
GDCLASS(ResourceFormatSaver, Reference);

View file

@ -30,10 +30,7 @@
#include "stream_peer_ssl.h"
#include "core/io/certs_compressed.gen.h"
#include "core/io/compression.h"
#include "core/os/file_access.h"
#include "core/project_settings.h"
#include "core/engine.h"
StreamPeerSSL *(*StreamPeerSSL::_create)() = NULL;
@ -44,22 +41,8 @@ StreamPeerSSL *StreamPeerSSL::create() {
return NULL;
}
StreamPeerSSL::LoadCertsFromMemory StreamPeerSSL::load_certs_func = NULL;
bool StreamPeerSSL::available = false;
void StreamPeerSSL::load_certs_from_memory(const PoolByteArray &p_memory) {
if (load_certs_func)
load_certs_func(p_memory);
}
void StreamPeerSSL::load_certs_from_file(String p_path) {
if (p_path != "") {
PoolByteArray certs = get_cert_file_as_array(p_path);
if (certs.size() > 0)
load_certs_func(certs);
}
}
bool StreamPeerSSL::is_available() {
return available;
}
@ -72,56 +55,11 @@ bool StreamPeerSSL::is_blocking_handshake_enabled() const {
return blocking_handshake;
}
PoolByteArray StreamPeerSSL::get_cert_file_as_array(String p_path) {
PoolByteArray out;
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (f) {
int flen = f->get_len();
out.resize(flen + 1);
PoolByteArray::Write w = out.write();
f->get_buffer(w.ptr(), flen);
w[flen] = 0; // Make sure it ends with string terminator
memdelete(f);
#ifdef DEBUG_ENABLED
print_verbose(vformat("Loaded certs from '%s'.", p_path));
#endif
}
return out;
}
PoolByteArray StreamPeerSSL::get_project_cert_array() {
PoolByteArray out;
String certs_path = GLOBAL_DEF("network/ssl/certificates", "");
ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt"));
if (certs_path != "") {
// Use certs defined in project settings.
return get_cert_file_as_array(certs_path);
}
#ifdef BUILTIN_CERTS_ENABLED
else {
// Use builtin certs only if user did not override it in project settings.
out.resize(_certs_uncompressed_size + 1);
PoolByteArray::Write w = out.write();
Compression::decompress(w.ptr(), _certs_uncompressed_size, _certs_compressed, _certs_compressed_size, Compression::MODE_DEFLATE);
w[_certs_uncompressed_size] = 0; // Make sure it ends with string terminator
#ifdef DEBUG_ENABLED
print_verbose("Loaded builtin certs");
#endif
}
#endif
return out;
}
void StreamPeerSSL::_bind_methods() {
ClassDB::bind_method(D_METHOD("poll"), &StreamPeerSSL::poll);
ClassDB::bind_method(D_METHOD("accept_stream", "base"), &StreamPeerSSL::accept_stream);
ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String()));
ClassDB::bind_method(D_METHOD("accept_stream", "stream", "private_key", "certificate", "chain"), &StreamPeerSSL::accept_stream, DEFVAL(Ref<X509Certificate>()));
ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname", "valid_certificate"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String()), DEFVAL(Ref<X509Certificate>()));
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status);
ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerSSL::disconnect_from_stream);
ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerSSL::set_blocking_handshake_enabled);

View file

@ -31,19 +31,16 @@
#ifndef STREAM_PEER_SSL_H
#define STREAM_PEER_SSL_H
#include "core/crypto/crypto.h"
#include "core/io/stream_peer.h"
class StreamPeerSSL : public StreamPeer {
GDCLASS(StreamPeerSSL, StreamPeer);
public:
typedef void (*LoadCertsFromMemory)(const PoolByteArray &p_certs);
protected:
static StreamPeerSSL *(*_create)();
static void _bind_methods();
static LoadCertsFromMemory load_certs_func;
static bool available;
bool blocking_handshake;
@ -61,18 +58,14 @@ public:
bool is_blocking_handshake_enabled() const;
virtual void poll() = 0;
virtual Error accept_stream(Ref<StreamPeer> p_base) = 0;
virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String()) = 0;
virtual Error accept_stream(Ref<StreamPeer> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>()) = 0;
virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String(), Ref<X509Certificate> p_valid_cert = Ref<X509Certificate>()) = 0;
virtual Status get_status() const = 0;
virtual void disconnect_from_stream() = 0;
static StreamPeerSSL *create();
static PoolByteArray get_cert_file_as_array(String p_path);
static PoolByteArray get_project_cert_array();
static void load_certs_from_file(String p_path);
static void load_certs_from_memory(const PoolByteArray &p_memory);
static bool is_available();
StreamPeerSSL();

View file

@ -67,8 +67,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
if (status == STATUS_READING_ID) {
memdelete(f);
ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
ERR_FAIL_V(RES());
ERR_FAIL_V_MSG(RES(), p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
} else {
break;
}
@ -79,8 +78,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
if (status == STATUS_READING_ID) {
memdelete(f);
ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected 'msgid', was expecting 'msgstr' while parsing: ");
ERR_FAIL_V(RES());
ERR_FAIL_V_MSG(RES(), p_path + ":" + itos(line) + " Unexpected 'msgid', was expecting 'msgstr' while parsing: ");
}
if (msg_id != "") {
@ -102,8 +100,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
if (status != STATUS_READING_ID) {
memdelete(f);
ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected 'msgstr', was expecting 'msgid' while parsing: ");
ERR_FAIL_V(RES());
ERR_FAIL_V_MSG(RES(), p_path + ":" + itos(line) + " Unexpected 'msgstr', was expecting 'msgid' while parsing: ");
}
l = l.substr(6, l.length()).strip_edges();
@ -118,11 +115,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
continue; //nothing to read or comment
}
if (!l.begins_with("\"") || status == STATUS_NONE) {
//not a string? failure!
ERR_EXPLAIN(p_path + ":" + itos(line) + " Invalid line '" + l + "' while parsing: ");
ERR_FAIL_V(RES());
}
ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, RES(), p_path + ":" + itos(line) + " Invalid line '" + l + "' while parsing: ");
l = l.substr(1, l.length());
//find final quote
@ -135,10 +128,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
}
}
if (end_pos == -1) {
ERR_EXPLAIN(p_path + ":" + itos(line) + " Expected '\"' at end of message while parsing file: ");
ERR_FAIL_V(RES());
}
ERR_FAIL_COND_V_MSG(end_pos == -1, RES(), p_path + ":" + itos(line) + " Expected '\"' at end of message while parsing file: ");
l = l.substr(0, end_pos);
l = l.c_unescape();
@ -163,10 +153,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
config = msg_str;
}
if (config == "") {
ERR_EXPLAIN("No config found in file: " + p_path);
ERR_FAIL_V(RES());
}
ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + p_path + ".");
Vector<String> configs = config.split("\n");
for (int i = 0; i < configs.size(); i++) {

View file

@ -443,10 +443,8 @@ String XMLParser::get_attribute_value(const String &p_name) const {
}
}
if (idx < 0) {
ERR_EXPLAIN("Attribute not found: " + p_name);
}
ERR_FAIL_COND_V(idx < 0, "");
ERR_FAIL_COND_V_MSG(idx < 0, "", "Attribute not found: " + p_name + ".");
return attributes[idx].value;
}

View file

@ -334,9 +334,6 @@ def make_version(template, nargs, argmax, const, ret):
elif (cmd == "noarg"):
for i in range(nargs + 1, argmax + 1):
outtext += data.replace("@", str(i))
elif (cmd == "noarg"):
for i in range(nargs + 1, argmax + 1):
outtext += data.replace("@", str(i))
from_pos = end + 1

View file

@ -33,12 +33,8 @@
#include "core/set.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
// based on the very nice implementation of rb-trees by:
// http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
// https://web.archive.org/web/20120507164830/http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
template <class K, class V, class C = Comparator<K>, class A = DefaultAllocator>
class Map {

View file

@ -2,37 +2,6 @@
Import('env')
env_math = env.Clone() # Maybe make one specific for crypto?
is_builtin = env["builtin_mbedtls"]
has_module = env["module_mbedtls_enabled"]
if is_builtin or not has_module:
# Use our headers for builtin or if the module is not going to be compiled.
# We decided not to depend on system mbedtls just for these few files that can
# be easily extracted.
env_math.Prepend(CPPPATH=["#thirdparty/mbedtls/include"])
# MbedTLS core functions (for CryptoCore).
# If the mbedtls module is compiled we don't need to add the .c files with our
# custom config since they will be built by the module itself.
# Only if the module is not enabled, we must compile here the required sources
# to make a "light" build with only the necessary mbedtls files.
if not has_module:
env_thirdparty = env_math.Clone()
env_thirdparty.disable_warnings()
# Custom config file
env_thirdparty.Append(CPPDEFINES=[('MBEDTLS_CONFIG_FILE', '\\"thirdparty/mbedtls/include/godot_core_mbedtls_config.h\\"')])
thirdparty_mbedtls_dir = "#thirdparty/mbedtls/library/"
thirdparty_mbedtls_sources = [
"aes.c",
"base64.c",
"md5.c",
"sha1.c",
"sha256.c",
"godot_core_mbedtls_platform.c"
]
thirdparty_mbedtls_sources = [thirdparty_mbedtls_dir + file for file in thirdparty_mbedtls_sources]
env_thirdparty.add_source_files(env.core_sources, thirdparty_mbedtls_sources)
env_math = env.Clone()
env_math.add_source_files(env.core_sources, "*.cpp")

View file

@ -40,7 +40,17 @@ int AStar::get_available_point_id() const {
return 1;
}
return points.back()->key() + 1;
// calculate our new next available point id if bigger than before or next id already contained in set of points.
if (points.has(last_free_id)) {
int cur_new_id = last_free_id;
while (points.has(cur_new_id)) {
cur_new_id++;
}
int &non_const = const_cast<int &>(last_free_id);
non_const = cur_new_id;
}
return last_free_id;
}
void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
@ -48,7 +58,10 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
ERR_FAIL_COND(p_id < 0);
ERR_FAIL_COND(p_weight_scale < 1);
if (!points.has(p_id)) {
Point *found_pt;
bool p_exists = points.lookup(p_id, found_pt);
if (!p_exists) {
Point *pt = memnew(Point);
pt->id = p_id;
pt->pos = p_pos;
@ -57,84 +70,98 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
pt->open_pass = 0;
pt->closed_pass = 0;
pt->enabled = true;
points[p_id] = pt;
points.set(p_id, pt);
} else {
points[p_id]->pos = p_pos;
points[p_id]->weight_scale = p_weight_scale;
found_pt->pos = p_pos;
found_pt->weight_scale = p_weight_scale;
}
}
Vector3 AStar::get_point_position(int p_id) const {
ERR_FAIL_COND_V(!points.has(p_id), Vector3());
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_V(!p_exists, Vector3());
return points[p_id]->pos;
return p->pos;
}
void AStar::set_point_position(int p_id, const Vector3 &p_pos) {
ERR_FAIL_COND(!points.has(p_id));
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND(!p_exists);
points[p_id]->pos = p_pos;
p->pos = p_pos;
}
real_t AStar::get_point_weight_scale(int p_id) const {
ERR_FAIL_COND_V(!points.has(p_id), 0);
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_V(!p_exists, 0);
return points[p_id]->weight_scale;
return p->weight_scale;
}
void AStar::set_point_weight_scale(int p_id, real_t p_weight_scale) {
ERR_FAIL_COND(!points.has(p_id));
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND(!p_exists);
ERR_FAIL_COND(p_weight_scale < 1);
points[p_id]->weight_scale = p_weight_scale;
p->weight_scale = p_weight_scale;
}
void AStar::remove_point(int p_id) {
ERR_FAIL_COND(!points.has(p_id));
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND(!p_exists);
Point *p = points[p_id];
for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) {
Segment s(p_id, E->get()->id);
Segment s(p_id, (*it.key));
segments.erase(s);
E->get()->neighbours.erase(p);
E->get()->unlinked_neighbours.erase(p);
(*it.value)->neighbours.remove(p->id);
(*it.value)->unlinked_neighbours.remove(p->id);
}
for (Set<Point *>::Element *E = p->unlinked_neighbours.front(); E; E = E->next()) {
for (OAHashMap<int, Point *>::Iterator it = p->unlinked_neighbours.iter(); it.valid; it = p->unlinked_neighbours.next_iter(it)) {
Segment s(p_id, E->get()->id);
Segment s(p_id, (*it.key));
segments.erase(s);
E->get()->neighbours.erase(p);
E->get()->unlinked_neighbours.erase(p);
(*it.value)->neighbours.remove(p->id);
(*it.value)->unlinked_neighbours.remove(p->id);
}
memdelete(p);
points.erase(p_id);
points.remove(p_id);
last_free_id = p_id;
}
void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) {
ERR_FAIL_COND(!points.has(p_id));
ERR_FAIL_COND(!points.has(p_with_id));
ERR_FAIL_COND(p_id == p_with_id);
Point *a = points[p_id];
Point *b = points[p_with_id];
a->neighbours.insert(b);
Point *a;
bool from_exists = points.lookup(p_id, a);
ERR_FAIL_COND(!from_exists);
if (bidirectional)
b->neighbours.insert(a);
else
b->unlinked_neighbours.insert(a);
Point *b;
bool to_exists = points.lookup(p_with_id, b);
ERR_FAIL_COND(!to_exists);
a->neighbours.set(b->id, b);
if (bidirectional) {
b->neighbours.set(a->id, a);
} else {
b->unlinked_neighbours.set(a->id, a);
}
Segment s(p_id, p_with_id);
if (s.from == p_id) {
@ -147,6 +174,7 @@ void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) {
segments.insert(s);
}
void AStar::disconnect_points(int p_id, int p_with_id) {
Segment s(p_id, p_with_id);
@ -154,12 +182,18 @@ void AStar::disconnect_points(int p_id, int p_with_id) {
segments.erase(s);
Point *a = points[p_id];
Point *b = points[p_with_id];
a->neighbours.erase(b);
a->unlinked_neighbours.erase(b);
b->neighbours.erase(a);
b->unlinked_neighbours.erase(a);
Point *a;
bool a_exists = points.lookup(p_id, a);
CRASH_COND(!a_exists);
Point *b;
bool b_exists = points.lookup(p_with_id, b);
CRASH_COND(!b_exists);
a->neighbours.remove(b->id);
a->unlinked_neighbours.remove(b->id);
b->neighbours.remove(a->id);
b->unlinked_neighbours.remove(a->id);
}
bool AStar::has_point(int p_id) const {
@ -171,8 +205,8 @@ Array AStar::get_points() {
Array point_list;
for (const Map<int, Point *>::Element *E = points.front(); E; E = E->next()) {
point_list.push_back(E->key());
for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) {
point_list.push_back(*(it.key));
}
return point_list;
@ -180,14 +214,14 @@ Array AStar::get_points() {
PoolVector<int> AStar::get_point_connections(int p_id) {
ERR_FAIL_COND_V(!points.has(p_id), PoolVector<int>());
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_V(!p_exists, PoolVector<int>());
PoolVector<int> point_list;
Point *p = points[p_id];
for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) {
point_list.push_back(E->get()->id);
for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
point_list.push_back((*it.key));
}
return point_list;
@ -201,27 +235,41 @@ bool AStar::are_points_connected(int p_id, int p_with_id) const {
void AStar::clear() {
for (const Map<int, Point *>::Element *E = points.front(); E; E = E->next()) {
memdelete(E->get());
last_free_id = 0;
for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) {
memdelete(*(it.value));
}
segments.clear();
points.clear();
}
int AStar::get_point_count() const {
return points.get_num_elements();
}
int AStar::get_point_capacity() const {
return points.get_capacity();
}
void AStar::reserve_space(int p_num_nodes) {
ERR_FAIL_COND_MSG(p_num_nodes <= 0, "New capacity must be greater than 0, was: " + itos(p_num_nodes) + ".");
ERR_FAIL_COND_MSG((uint32_t)p_num_nodes < points.get_capacity(), "New capacity must be greater than current capacity: " + itos(points.get_capacity()) + ", new was: " + itos(p_num_nodes) + ".");
points.reserve(p_num_nodes);
}
int AStar::get_closest_point(const Vector3 &p_point) const {
int closest_id = -1;
real_t closest_dist = 1e20;
for (const Map<int, Point *>::Element *E = points.front(); E; E = E->next()) {
for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) {
if (!E->get()->enabled)
continue; //Disabled points should not be considered
real_t d = p_point.distance_squared_to(E->get()->pos);
if (!(*it.value)->enabled) continue; // Disabled points should not be considered.
real_t d = p_point.distance_squared_to((*it.value)->pos);
if (closest_id < 0 || d < closest_dist) {
closest_dist = d;
closest_id = E->key();
closest_id = *(it.key);
}
}
@ -230,8 +278,8 @@ int AStar::get_closest_point(const Vector3 &p_point) const {
Vector3 AStar::get_closest_position_in_segment(const Vector3 &p_point) const {
real_t closest_dist = 1e20;
bool found = false;
real_t closest_dist = 1e20;
Vector3 closest_point;
for (const Set<Segment>::Element *E = segments.front(); E; E = E->next()) {
@ -262,8 +310,7 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
pass++;
if (!end_point->enabled)
return false;
if (!end_point->enabled) return false;
bool found_route = false;
@ -272,13 +319,9 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
begin_point->g_score = 0;
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
open_list.push_back(begin_point);
while (true) {
if (open_list.size() == 0) // No path found
break;
while (!open_list.empty()) {
Point *p = open_list[0]; // The currently processed point
@ -291,24 +334,23 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
open_list.remove(open_list.size() - 1);
p->closed_pass = pass; // Mark the point as closed
for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) {
for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
Point *e = E->get(); // The neighbour point
Point *e = *(it.value); // The neighbour point
if (!e->enabled || e->closed_pass == pass)
if (!e->enabled || e->closed_pass == pass) {
continue;
}
real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * e->weight_scale;
bool new_point = false;
if (e->open_pass != pass) { // The point wasn't inside the open list
if (e->open_pass != pass) { // The point wasn't inside the open list.
e->open_pass = pass;
open_list.push_back(e);
new_point = true;
} else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous
} else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous.
continue;
}
@ -316,10 +358,11 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
e->g_score = tentative_g_score;
e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
if (new_point) // The position of the new points is already known
if (new_point) { // The position of the new points is already known.
sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw());
else
} else {
sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw());
}
}
}
@ -331,7 +374,15 @@ float AStar::_estimate_cost(int p_from_id, int p_to_id) {
if (get_script_instance() && get_script_instance()->has_method(SceneStringNames::get_singleton()->_estimate_cost))
return get_script_instance()->call(SceneStringNames::get_singleton()->_estimate_cost, p_from_id, p_to_id);
return points[p_from_id]->pos.distance_to(points[p_to_id]->pos);
Point *from_point;
bool from_exists = points.lookup(p_from_id, from_point);
CRASH_COND(!from_exists);
Point *to_point;
bool to_exists = points.lookup(p_to_id, to_point);
CRASH_COND(!to_exists);
return from_point->pos.distance_to(to_point->pos);
}
float AStar::_compute_cost(int p_from_id, int p_to_id) {
@ -339,16 +390,26 @@ float AStar::_compute_cost(int p_from_id, int p_to_id) {
if (get_script_instance() && get_script_instance()->has_method(SceneStringNames::get_singleton()->_compute_cost))
return get_script_instance()->call(SceneStringNames::get_singleton()->_compute_cost, p_from_id, p_to_id);
return points[p_from_id]->pos.distance_to(points[p_to_id]->pos);
Point *from_point;
bool from_exists = points.lookup(p_from_id, from_point);
CRASH_COND(!from_exists);
Point *to_point;
bool to_exists = points.lookup(p_to_id, to_point);
CRASH_COND(!to_exists);
return from_point->pos.distance_to(to_point->pos);
}
PoolVector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) {
ERR_FAIL_COND_V(!points.has(p_from_id), PoolVector<Vector3>());
ERR_FAIL_COND_V(!points.has(p_to_id), PoolVector<Vector3>());
Point *a;
bool from_exists = points.lookup(p_from_id, a);
ERR_FAIL_COND_V(!from_exists, PoolVector<Vector3>());
Point *a = points[p_from_id];
Point *b = points[p_to_id];
Point *b;
bool to_exists = points.lookup(p_to_id, b);
ERR_FAIL_COND_V(!to_exists, PoolVector<Vector3>());
if (a == b) {
PoolVector<Vector3> ret;
@ -360,11 +421,8 @@ PoolVector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) {
Point *end_point = b;
bool found_route = _solve(begin_point, end_point);
if (!found_route) return PoolVector<Vector3>();
if (!found_route)
return PoolVector<Vector3>();
// Midpoints
Point *p = end_point;
int pc = 1; // Begin point
while (p != begin_point) {
@ -393,11 +451,13 @@ PoolVector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) {
PoolVector<int> AStar::get_id_path(int p_from_id, int p_to_id) {
ERR_FAIL_COND_V(!points.has(p_from_id), PoolVector<int>());
ERR_FAIL_COND_V(!points.has(p_to_id), PoolVector<int>());
Point *a;
bool from_exists = points.lookup(p_from_id, a);
ERR_FAIL_COND_V(!from_exists, PoolVector<int>());
Point *a = points[p_from_id];
Point *b = points[p_to_id];
Point *b;
bool to_exists = points.lookup(p_to_id, b);
ERR_FAIL_COND_V(!to_exists, PoolVector<int>());
if (a == b) {
PoolVector<int> ret;
@ -409,11 +469,8 @@ PoolVector<int> AStar::get_id_path(int p_from_id, int p_to_id) {
Point *end_point = b;
bool found_route = _solve(begin_point, end_point);
if (!found_route) return PoolVector<int>();
if (!found_route)
return PoolVector<int>();
// Midpoints
Point *p = end_point;
int pc = 1; // Begin point
while (p != begin_point) {
@ -442,16 +499,20 @@ PoolVector<int> AStar::get_id_path(int p_from_id, int p_to_id) {
void AStar::set_point_disabled(int p_id, bool p_disabled) {
ERR_FAIL_COND(!points.has(p_id));
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND(!p_exists);
points[p_id]->enabled = !p_disabled;
p->enabled = !p_disabled;
}
bool AStar::is_point_disabled(int p_id) const {
ERR_FAIL_COND_V(!points.has(p_id), false);
Point *p;
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_V(!p_exists, false);
return !points[p_id]->enabled;
return !p->enabled;
}
void AStar::_bind_methods() {
@ -474,6 +535,9 @@ void AStar::_bind_methods() {
ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar::disconnect_points);
ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id"), &AStar::are_points_connected);
ClassDB::bind_method(D_METHOD("get_point_count"), &AStar::get_point_count);
ClassDB::bind_method(D_METHOD("get_point_capacity"), &AStar::get_point_capacity);
ClassDB::bind_method(D_METHOD("reserve_space", "num_nodes"), &AStar::reserve_space);
ClassDB::bind_method(D_METHOD("clear"), &AStar::clear);
ClassDB::bind_method(D_METHOD("get_closest_point", "to_position"), &AStar::get_closest_point);
@ -487,13 +551,11 @@ void AStar::_bind_methods() {
}
AStar::AStar() {
last_free_id = 0;
pass = 1;
}
AStar::~AStar() {
pass = 1;
clear();
}
@ -560,10 +622,22 @@ bool AStar2D::are_points_connected(int p_id, int p_with_id) const {
return astar.are_points_connected(p_id, p_with_id);
}
int AStar2D::get_point_count() const {
return astar.get_point_count();
}
int AStar2D::get_point_capacity() const {
return astar.get_point_capacity();
}
void AStar2D::clear() {
astar.clear();
}
void AStar2D::reserve_space(int p_num_nodes) {
astar.reserve_space(p_num_nodes);
}
int AStar2D::get_closest_point(const Vector2 &p_point) const {
return astar.get_closest_point(Vector3(p_point.x, p_point.y, 0));
}
@ -614,6 +688,9 @@ void AStar2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar2D::disconnect_points);
ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id"), &AStar2D::are_points_connected);
ClassDB::bind_method(D_METHOD("get_point_count"), &AStar2D::get_point_count);
ClassDB::bind_method(D_METHOD("get_point_capacity"), &AStar2D::get_point_capacity);
ClassDB::bind_method(D_METHOD("reserve_space", "num_nodes"), &AStar2D::reserve_space);
ClassDB::bind_method(D_METHOD("clear"), &AStar2D::clear);
ClassDB::bind_method(D_METHOD("get_closest_point", "to_position"), &AStar2D::get_closest_point);

View file

@ -31,8 +31,8 @@
#ifndef ASTAR_H
#define ASTAR_H
#include "core/oa_hash_map.h"
#include "core/reference.h"
#include "core/self_list.h"
/**
A* pathfinding algorithm
@ -44,19 +44,21 @@ class AStar : public Reference {
GDCLASS(AStar, Reference);
uint64_t pass;
struct Point {
Point() :
neighbours(4u),
unlinked_neighbours(4u) {}
int id;
Vector3 pos;
real_t weight_scale;
bool enabled;
Set<Point *> neighbours;
Set<Point *> unlinked_neighbours;
OAHashMap<int, Point *> neighbours;
OAHashMap<int, Point *> unlinked_neighbours;
// Used for pathfinding
// Used for pathfinding.
Point *prev_point;
real_t g_score;
real_t f_score;
@ -64,16 +66,15 @@ class AStar : public Reference {
uint64_t closed_pass;
};
Map<int, Point *> points;
struct SortPoints {
_FORCE_INLINE_ bool operator()(const Point *A, const Point *B) const { // Returns true when the Point A is worse than Point B
if (A->f_score > B->f_score)
_FORCE_INLINE_ bool operator()(const Point *A, const Point *B) const { // Returns true when the Point A is worse than Point B.
if (A->f_score > B->f_score) {
return true;
else if (A->f_score < B->f_score)
} else if (A->f_score < B->f_score) {
return false;
else
return A->g_score < B->g_score; // If the f_costs are the same then prioritize the points that are further away from the start
} else {
return A->g_score < B->g_score; // If the f_costs are the same then prioritize the points that are further away from the start.
}
}
};
@ -101,6 +102,10 @@ class AStar : public Reference {
}
};
int last_free_id;
uint64_t pass;
OAHashMap<int, Point *> points;
Set<Segment> segments;
bool _solve(Point *begin_point, Point *end_point);
@ -131,6 +136,9 @@ public:
void disconnect_points(int p_id, int p_with_id);
bool are_points_connected(int p_id, int p_with_id) const;
int get_point_count() const;
int get_point_capacity() const;
void reserve_space(int p_num_nodes);
void clear();
int get_closest_point(const Vector3 &p_point) const;
@ -170,6 +178,9 @@ public:
void disconnect_points(int p_id, int p_with_id);
bool are_points_connected(int p_id, int p_with_id) const;
int get_point_count() const;
int get_point_capacity() const;
void reserve_space(int p_num_nodes);
void clear();
int get_closest_point(const Vector2 &p_point) const;

View file

@ -618,10 +618,7 @@ Basis::operator String() const {
Quat Basis::get_quat() const {
#ifdef MATH_CHECKS
if (!is_rotation()) {
ERR_EXPLAIN("Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead.");
ERR_FAIL_V(Quat());
}
ERR_FAIL_COND_V_MSG(!is_rotation(), Quat(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead.");
#endif
/* Allow getting a quaternion from an unnormalized transform */
Basis m = *this;

View file

@ -36,10 +36,6 @@
#include "core/math/quat.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class Basis {
public:
Vector3 elements[3];

View file

@ -38,9 +38,7 @@
#include "core/pool_vector.h"
#include "core/variant.h"
#include "core/vector.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class BSP_Tree {
public:
enum {

View file

@ -302,8 +302,8 @@ Vector<Plane> CameraMatrix::get_projection_planes(const Transform &p_transform)
/** Fast Plane Extraction from combined modelview/projection matrices.
* References:
* http://www.markmorley.com/opengl/frustumculling.html
* http://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf
* https://web.archive.org/web/20011221205252/http://www.markmorley.com/opengl/frustumculling.html
* https://web.archive.org/web/20061020020112/http://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf
*/
Vector<Plane> planes;

View file

@ -34,10 +34,6 @@
#include "core/math/rect2.h"
#include "core/math/transform.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
struct CameraMatrix {
enum Planes {

View file

@ -80,11 +80,11 @@ public:
}
static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) {
if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]))) {
if (p_vertices[p_a.edge[0]] == p_vertices[p_b.edge[0]] && p_vertices[p_a.edge[1]] == p_vertices[p_b.edge[1]]) {
return true;
}
if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]))) {
if (p_vertices[p_a.edge[0]] == p_vertices[p_b.edge[1]] && p_vertices[p_a.edge[1]] == p_vertices[p_b.edge[0]]) {
return true;
}

View file

@ -2161,10 +2161,8 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu
}
Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) {
if (error_set) {
ERR_EXPLAIN("There was previously a parse error: " + error_str);
ERR_FAIL_V(Variant());
}
ERR_FAIL_COND_V_MSG(error_set, Variant(), "There was previously a parse error: " + error_str + ".");
execution_error = false;
Variant output;
@ -2173,10 +2171,7 @@ Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) {
if (err) {
execution_error = true;
error_str = error_txt;
if (p_show_error) {
ERR_EXPLAIN(error_str);
ERR_FAIL_V(Variant());
}
ERR_FAIL_COND_V_MSG(p_show_error, Variant(), error_str);
}
return output;

View file

@ -34,9 +34,10 @@
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/triangulator.h"
#define SCALE_FACTOR 100000.0 // based on CMP_EPSILON
#define SCALE_FACTOR 100000.0 // Based on CMP_EPSILON.
/* this implementation is very inefficient, commenting unless bugs happen. See the other one.
// This implementation is very inefficient, commenting unless bugs happen. See the other one.
/*
bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) {
Vector<int> indices = Geometry::triangulate_polygon(p_polygon);
@ -124,8 +125,8 @@ struct _FaceClassify {
};
static bool _connect_faces(_FaceClassify *p_faces, int len, int p_group) {
/* connect faces, error will occur if an edge is shared between more than 2 faces */
/* clear connections */
// Connect faces, error will occur if an edge is shared between more than 2 faces.
// Clear connections.
bool error = false;
@ -195,13 +196,6 @@ static bool _connect_faces(_FaceClassify *p_faces, int len, int p_group) {
if (p_faces[i].links[j].face == -1)
p_faces[i].valid = false;
}
/*printf("face %i is valid: %i, group %i. connected to %i:%i,%i:%i,%i:%i\n",i,p_faces[i].valid,p_faces[i].group,
p_faces[i].links[0].face,
p_faces[i].links[0].edge,
p_faces[i].links[1].face,
p_faces[i].links[1].edge,
p_faces[i].links[2].face,
p_faces[i].links[2].edge);*/
}
return error;
}
@ -249,10 +243,10 @@ PoolVector<PoolVector<Face3> > Geometry::separate_objects(PoolVector<Face3> p_ar
if (error) {
ERR_FAIL_COND_V(error, PoolVector<PoolVector<Face3> >()); // invalid geometry
ERR_FAIL_COND_V(error, PoolVector<PoolVector<Face3> >()); // Invalid geometry.
}
/* group connected faces in separate objects */
// Group connected faces in separate objects.
int group = 0;
for (int i = 0; i < len; i++) {
@ -264,7 +258,7 @@ PoolVector<PoolVector<Face3> > Geometry::separate_objects(PoolVector<Face3> p_ar
}
}
/* group connected faces in separate objects */
// Group connected faces in separate objects.
for (int i = 0; i < len; i++) {
@ -376,7 +370,7 @@ static inline void _plot_face(uint8_t ***p_cell_status, int x, int y, int z, int
static inline void _mark_outside(uint8_t ***p_cell_status, int x, int y, int z, int len_x, int len_y, int len_z) {
if (p_cell_status[x][y][z] & 3)
return; // nothing to do, already used and/or visited
return; // Nothing to do, already used and/or visited.
p_cell_status[x][y][z] = _CELL_PREV_FIRST;
@ -384,29 +378,20 @@ static inline void _mark_outside(uint8_t ***p_cell_status, int x, int y, int z,
uint8_t &c = p_cell_status[x][y][z];
//printf("at %i,%i,%i\n",x,y,z);
if ((c & _CELL_STEP_MASK) == _CELL_STEP_NONE) {
/* Haven't been in here, mark as outside */
// Haven't been in here, mark as outside.
p_cell_status[x][y][z] |= _CELL_EXTERIOR;
//printf("not marked as anything, marking exterior\n");
}
//printf("cell step is %i\n",(c&_CELL_STEP_MASK));
if ((c & _CELL_STEP_MASK) != _CELL_STEP_DONE) {
/* if not done, increase step */
// If not done, increase step.
c += 1 << 2;
//printf("incrementing cell step\n");
}
if ((c & _CELL_STEP_MASK) == _CELL_STEP_DONE) {
/* Go back */
//printf("done, going back a cell\n");
// Go back.
switch (c & _CELL_PREV_MASK) {
case _CELL_PREV_FIRST: {
//printf("at end, finished marking\n");
return;
} break;
case _CELL_PREV_Y_POS: {
@ -440,8 +425,6 @@ static inline void _mark_outside(uint8_t ***p_cell_status, int x, int y, int z,
continue;
}
//printf("attempting new cell!\n");
int next_x = x, next_y = y, next_z = z;
uint8_t prev = 0;
@ -475,8 +458,6 @@ static inline void _mark_outside(uint8_t ***p_cell_status, int x, int y, int z,
default: ERR_FAIL();
}
//printf("testing if new cell will be ok...!\n");
if (next_x < 0 || next_x >= len_x)
continue;
if (next_y < 0 || next_y >= len_y)
@ -484,13 +465,9 @@ static inline void _mark_outside(uint8_t ***p_cell_status, int x, int y, int z,
if (next_z < 0 || next_z >= len_z)
continue;
//printf("testing if new cell is traversable\n");
if (p_cell_status[next_x][next_y][next_z] & 3)
continue;
//printf("move to it\n");
x = next_x;
y = next_y;
z = next_z;
@ -507,17 +484,6 @@ static inline void _build_faces(uint8_t ***p_cell_status, int x, int y, int z, i
if (p_cell_status[x][y][z] & _CELL_EXTERIOR)
return;
/* static const Vector3 vertices[8]={
Vector3(0,0,0),
Vector3(0,0,1),
Vector3(0,1,0),
Vector3(0,1,1),
Vector3(1,0,0),
Vector3(1,0,1),
Vector3(1,1,0),
Vector3(1,1,1),
};
*/
#define vert(m_idx) Vector3(((m_idx)&4) >> 2, ((m_idx)&2) >> 1, (m_idx)&1)
static const uint8_t indices[6][4] = {
@ -529,22 +495,6 @@ static inline void _build_faces(uint8_t ***p_cell_status, int x, int y, int z, i
{ 0, 4, 6, 2 },
};
/*
{0,1,2,3},
{0,1,4,5},
{0,2,4,6},
{4,5,6,7},
{2,3,7,6},
{1,3,5,7},
{0,2,3,1},
{0,1,5,4},
{0,4,6,2},
{7,6,4,5},
{7,3,2,6},
{7,5,1,3},
*/
for (int i = 0; i < 6; i++) {
@ -607,9 +557,9 @@ PoolVector<Face3> Geometry::wrap_geometry(PoolVector<Face3> p_array, real_t *p_e
}
}
global_aabb.grow_by(0.01); // avoid numerical error
global_aabb.grow_by(0.01); // Avoid numerical error.
// determine amount of cells in grid axis
// Determine amount of cells in grid axis.
int div_x, div_y, div_z;
if (global_aabb.size.x / _MIN_SIZE < _MAX_LENGTH)
@ -632,7 +582,7 @@ PoolVector<Face3> Geometry::wrap_geometry(PoolVector<Face3> p_array, real_t *p_e
voxelsize.y /= div_y;
voxelsize.z /= div_z;
// create and initialize cells to zero
// Create and initialize cells to zero.
uint8_t ***cell_status = memnew_arr(uint8_t **, div_x);
for (int i = 0; i < div_x; i++) {
@ -650,7 +600,7 @@ PoolVector<Face3> Geometry::wrap_geometry(PoolVector<Face3> p_array, real_t *p_e
}
}
// plot faces into cells
// Plot faces into cells.
for (int i = 0; i < face_count; i++) {
@ -662,7 +612,7 @@ PoolVector<Face3> Geometry::wrap_geometry(PoolVector<Face3> p_array, real_t *p_e
_plot_face(cell_status, 0, 0, 0, div_x, div_y, div_z, voxelsize, f);
}
// determine which cells connect to the outside by traversing the outside and recursively flood-fill marking
// Determine which cells connect to the outside by traversing the outside and recursively flood-fill marking.
for (int i = 0; i < div_x; i++) {
@ -691,7 +641,7 @@ PoolVector<Face3> Geometry::wrap_geometry(PoolVector<Face3> p_array, real_t *p_e
}
}
// build faces for the inside-outside cell divisors
// Build faces for the inside-outside cell divisors.
PoolVector<Face3> wrapped_faces;
@ -706,7 +656,7 @@ PoolVector<Face3> Geometry::wrap_geometry(PoolVector<Face3> p_array, real_t *p_e
}
}
// transform face vertices to global coords
// Transform face vertices to global coords.
int wrapped_faces_count = wrapped_faces.size();
PoolVector<Face3>::Write wrapped_facesw = wrapped_faces.write();
@ -753,7 +703,7 @@ Vector<Vector<Vector2> > Geometry::decompose_polygon_in_convex(Vector<Point2> po
inp.SetOrientation(TRIANGULATOR_CCW);
in_poly.push_back(inp);
TriangulatorPartition tpart;
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { // Failed.
ERR_PRINT("Convex decomposing failed!");
return decomp;
}
@ -781,7 +731,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
#define SUBPLANE_SIZE 1024.0
real_t subplane_size = 1024.0; // should compute this from the actual plane
real_t subplane_size = 1024.0; // Should compute this from the actual plane.
for (int i = 0; i < p_planes.size(); i++) {
Plane p = p_planes[i];
@ -789,7 +739,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
Vector3 ref = Vector3(0.0, 1.0, 0.0);
if (ABS(p.normal.dot(ref)) > 0.95)
ref = Vector3(0.0, 0.0, 1.0); // change axis
ref = Vector3(0.0, 0.0, 1.0); // Change axis.
Vector3 right = p.normal.cross(ref).normalized();
Vector3 up = p.normal.cross(right).normalized();
@ -827,20 +777,20 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
real_t dist0 = clip.distance_to(edge0_A);
real_t dist1 = clip.distance_to(edge1_A);
if (dist0 <= 0) { // behind plane
if (dist0 <= 0) { // Behind plane.
new_vertices.push_back(vertices[k]);
}
// check for different sides and non coplanar
// Check for different sides and non coplanar.
if ((dist0 * dist1) < 0) {
// calculate intersection
// Calculate intersection.
Vector3 rel = edge1_A - edge0_A;
real_t den = clip.normal.dot(rel);
if (Math::is_zero_approx(den))
continue; // point too short
continue; // Point too short.
real_t dist = -(clip.normal.dot(edge0_A) - clip.d) / den;
Vector3 inters = edge0_A + rel * dist;
@ -854,11 +804,11 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
if (vertices.size() < 3)
continue;
//result is a clockwise face
// Result is a clockwise face.
MeshData::Face face;
// add face indices
// Add face indices.
for (int j = 0; j < vertices.size(); j++) {
int idx = -1;
@ -882,7 +832,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
face.plane = p;
mesh.faces.push_back(face);
//add edge
// Add edge.
for (int j = 0; j < face.indices.size(); j++) {
@ -972,7 +922,7 @@ PoolVector<Plane> Geometry::build_sphere_planes(real_t p_radius, int p_lats, int
for (int j = 1; j <= p_lats; j++) {
//todo this is stupid, fix
// FIXME: This is stupid.
Vector3 angle = normal.linear_interpolate(axis, j / (real_t)p_lats).normalized();
Vector3 pos = angle * p_radius;
planes.push_back(Plane(pos, angle));
@ -1032,12 +982,12 @@ struct _AtlasWorkRectResult {
void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size) {
//super simple, almost brute force scanline stacking fitter
//it's pretty basic for now, but it tries to make sure that the aspect ratio of the
//resulting atlas is somehow square. This is necessary because video cards have limits
//on texture size (usually 2048 or 4096), so the more square a texture, the more chances
//it will work in every hardware.
// for example, it will prioritize a 1024x1024 atlas (works everywhere) instead of a
// Super simple, almost brute force scanline stacking fitter.
// It's pretty basic for now, but it tries to make sure that the aspect ratio of the
// resulting atlas is somehow square. This is necessary because video cards have limits.
// On texture size (usually 2048 or 4096), so the more square a texture, the more chances.
// It will work in every hardware.
// For example, it will prioritize a 1024x1024 atlas (works everywhere) instead of a
// 256x8192 atlas (won't work anywhere).
ERR_FAIL_COND(p_rects.size() == 0);
@ -1066,7 +1016,7 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu
for (int j = 0; j < w; j++)
hmax.write[j] = 0;
//place them
// Place them.
int ofs = 0;
int limit_h = 0;
for (int j = 0; j < wrects.size(); j++) {
@ -1101,7 +1051,7 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu
if (end_w > max_w)
max_w = end_w;
if (ofs == 0 || end_h > limit_h) //while h limit not reached, keep stacking
if (ofs == 0 || end_h > limit_h) // While h limit not reached, keep stacking.
ofs += wrects[j].s.width;
}
@ -1112,7 +1062,7 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu
results.push_back(result);
}
//find the result with the best aspect ratio
// Find the result with the best aspect ratio.
int best = -1;
real_t best_aspect = 1e20;
@ -1152,7 +1102,7 @@ Vector<Vector<Point2> > Geometry::_polypaths_do_operation(PolyBooleanOperation p
}
Path path_a, path_b;
// Need to scale points (Clipper's requirement for robust computation)
// Need to scale points (Clipper's requirement for robust computation).
for (int i = 0; i != p_polypath_a.size(); ++i) {
path_a << IntPoint(p_polypath_a[i].x * SCALE_FACTOR, p_polypath_a[i].y * SCALE_FACTOR);
}
@ -1160,19 +1110,19 @@ Vector<Vector<Point2> > Geometry::_polypaths_do_operation(PolyBooleanOperation p
path_b << IntPoint(p_polypath_b[i].x * SCALE_FACTOR, p_polypath_b[i].y * SCALE_FACTOR);
}
Clipper clp;
clp.AddPath(path_a, ptSubject, !is_a_open); // forward compatible with Clipper 10.0.0
clp.AddPath(path_b, ptClip, true); // polylines cannot be set as clip
clp.AddPath(path_a, ptSubject, !is_a_open); // Forward compatible with Clipper 10.0.0.
clp.AddPath(path_b, ptClip, true); // Polylines cannot be set as clip.
Paths paths;
if (is_a_open) {
PolyTree tree; // needed to populate polylines
PolyTree tree; // Needed to populate polylines.
clp.Execute(op, tree);
OpenPathsFromPolyTree(tree, paths);
} else {
clp.Execute(op, paths); // works on closed polygons only
clp.Execute(op, paths); // Works on closed polygons only.
}
// Have to scale points down now
// Have to scale points down now.
Vector<Vector<Point2> > polypaths;
for (Paths::size_type i = 0; i < paths.size(); ++i) {
@ -1214,16 +1164,16 @@ Vector<Vector<Point2> > Geometry::_polypath_offset(const Vector<Point2> &p_polyp
ClipperOffset co;
Path path;
// Need to scale points (Clipper's requirement for robust computation)
// Need to scale points (Clipper's requirement for robust computation).
for (int i = 0; i != p_polypath.size(); ++i) {
path << IntPoint(p_polypath[i].x * SCALE_FACTOR, p_polypath[i].y * SCALE_FACTOR);
}
co.AddPath(path, jt, et);
Paths paths;
co.Execute(paths, p_delta * SCALE_FACTOR); // inflate/deflate
co.Execute(paths, p_delta * SCALE_FACTOR); // Inflate/deflate.
// Have to scale points down now
// Have to scale points down now.
Vector<Vector<Point2> > polypaths;
for (Paths::size_type i = 0; i < paths.size(); ++i) {

View file

@ -41,47 +41,43 @@
#include "core/print_string.h"
#include "core/vector.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class Geometry {
Geometry();
public:
static real_t get_closest_points_between_segments(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2, Vector2 &c1, Vector2 &c2) {
Vector2 d1 = q1 - p1; // Direction vector of segment S1
Vector2 d2 = q2 - p2; // Direction vector of segment S2
Vector2 d1 = q1 - p1; // Direction vector of segment S1.
Vector2 d2 = q2 - p2; // Direction vector of segment S2.
Vector2 r = p1 - p2;
real_t a = d1.dot(d1); // Squared length of segment S1, always nonnegative
real_t e = d2.dot(d2); // Squared length of segment S2, always nonnegative
real_t a = d1.dot(d1); // Squared length of segment S1, always nonnegative.
real_t e = d2.dot(d2); // Squared length of segment S2, always nonnegative.
real_t f = d2.dot(r);
real_t s, t;
// Check if either or both segments degenerate into points
// Check if either or both segments degenerate into points.
if (a <= CMP_EPSILON && e <= CMP_EPSILON) {
// Both segments degenerate into points
// Both segments degenerate into points.
c1 = p1;
c2 = p2;
return Math::sqrt((c1 - c2).dot(c1 - c2));
}
if (a <= CMP_EPSILON) {
// First segment degenerates into a point
// First segment degenerates into a point.
s = 0.0;
t = f / e; // s = 0 => t = (b*s + f) / e = f / e
t = CLAMP(t, 0.0, 1.0);
} else {
real_t c = d1.dot(r);
if (e <= CMP_EPSILON) {
// Second segment degenerates into a point
// Second segment degenerates into a point.
t = 0.0;
s = CLAMP(-c / a, 0.0, 1.0); // t = 0 => s = (b*t - c) / a = -c / a
} else {
// The general nondegenerate case starts here
// The general nondegenerate case starts here.
real_t b = d1.dot(d2);
real_t denom = a * e - b * b; // Always nonnegative
real_t denom = a * e - b * b; // Always nonnegative.
// If segments not parallel, compute closest point on L1 to L2 and
// clamp to segment S1. Else pick arbitrary s (here 0)
// clamp to segment S1. Else pick arbitrary s (here 0).
if (denom != 0.0) {
s = CLAMP((b * f - c * e) / denom, 0.0, 1.0);
} else
@ -92,7 +88,7 @@ public:
//If t in [0,1] done. Else clamp t, recompute s for the new value
// of t using s = Dot((P2 + D2*t) - P1,D1) / Dot(D1,D1)= (t*b - c) / a
// and clamp s to [0, 1]
// and clamp s to [0, 1].
if (t < 0.0) {
t = 0.0;
s = CLAMP(-c / a, 0.0, 1.0);
@ -109,14 +105,14 @@ public:
static void get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2, Vector3 &c1, Vector3 &c2) {
//do the function 'd' as defined by pb. I think is is dot product of some sort
// Do the function 'd' as defined by pb. I think is is dot product of some sort.
#define d_of(m, n, o, p) ((m.x - n.x) * (o.x - p.x) + (m.y - n.y) * (o.y - p.y) + (m.z - n.z) * (o.z - p.z))
//calculate the parametric position on the 2 curves, mua and mub
// Calculate the parametric position on the 2 curves, mua and mub.
real_t mua = (d_of(p1, q1, q2, q1) * d_of(q2, q1, p2, p1) - d_of(p1, q1, p2, p1) * d_of(q2, q1, q2, q1)) / (d_of(p2, p1, p2, p1) * d_of(q2, q1, q2, q1) - d_of(q2, q1, p2, p1) * d_of(q2, q1, p2, p1));
real_t mub = (d_of(p1, q1, q2, q1) + mua * d_of(q2, q1, p2, p1)) / d_of(q2, q1, q2, q1);
//clip the value between [0..1] constraining the solution to lie on the original curves
// Clip the value between [0..1] constraining the solution to lie on the original curves.
if (mua < 0) mua = 0;
if (mub < 0) mub = 0;
if (mua > 1) mua = 1;
@ -129,38 +125,38 @@ public:
Vector3 u = p_to_a - p_from_a;
Vector3 v = p_to_b - p_from_b;
Vector3 w = p_from_a - p_to_a;
real_t a = u.dot(u); // always >= 0
real_t a = u.dot(u); // Always >= 0
real_t b = u.dot(v);
real_t c = v.dot(v); // always >= 0
real_t c = v.dot(v); // Always >= 0
real_t d = u.dot(w);
real_t e = v.dot(w);
real_t D = a * c - b * b; // always >= 0
real_t D = a * c - b * b; // Always >= 0
real_t sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0
real_t tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
// compute the line parameters of the two closest points
if (D < CMP_EPSILON) { // the lines are almost parallel
sN = 0.0; // force using point P0 on segment S1
sD = 1.0; // to prevent possible division by 0.0 later
// Compute the line parameters of the two closest points.
if (D < CMP_EPSILON) { // The lines are almost parallel.
sN = 0.0; // Force using point P0 on segment S1
sD = 1.0; // to prevent possible division by 0.0 later.
tN = e;
tD = c;
} else { // get the closest points on the infinite lines
} else { // Get the closest points on the infinite lines
sN = (b * e - c * d);
tN = (a * e - b * d);
if (sN < 0.0) { // sc < 0 => the s=0 edge is visible
if (sN < 0.0) { // sc < 0 => the s=0 edge is visible.
sN = 0.0;
tN = e;
tD = c;
} else if (sN > sD) { // sc > 1 => the s=1 edge is visible
} else if (sN > sD) { // sc > 1 => the s=1 edge is visible.
sN = sD;
tN = e + b;
tD = c;
}
}
if (tN < 0.0) { // tc < 0 => the t=0 edge is visible
if (tN < 0.0) { // tc < 0 => the t=0 edge is visible.
tN = 0.0;
// recompute sc for this edge
// Recompute sc for this edge.
if (-d < 0.0)
sN = 0.0;
else if (-d > a)
@ -169,9 +165,9 @@ public:
sN = -d;
sD = a;
}
} else if (tN > tD) { // tc > 1 => the t=1 edge is visible
} else if (tN > tD) { // tc > 1 => the t=1 edge is visible.
tN = tD;
// recompute sc for this edge
// Recompute sc for this edge.
if ((-d + b) < 0.0)
sN = 0;
else if ((-d + b) > a)
@ -181,14 +177,14 @@ public:
sD = a;
}
}
// finally do the division to get sc and tc
// Finally do the division to get sc and tc.
sc = (Math::is_zero_approx(sN) ? 0.0 : sN / sD);
tc = (Math::is_zero_approx(tN) ? 0.0 : tN / tD);
// get the difference of the two closest points
// Get the difference of the two closest points.
Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
return dP.length(); // return the closest distance
return dP.length(); // Return the closest distance.
}
static inline bool ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2, Vector3 *r_res = 0) {
@ -196,7 +192,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = p_dir.cross(e2);
real_t a = e1.dot(h);
if (Math::is_zero_approx(a)) // parallel test
if (Math::is_zero_approx(a)) // Parallel test.
return false;
real_t f = 1.0 / a;
@ -214,16 +210,15 @@ public:
if (v < 0.0 || u + v > 1.0)
return false;
// at this stage we can compute t to find out where
// the intersection point is on the line
// At this stage we can compute t to find out where
// the intersection point is on the line.
real_t t = f * e2.dot(q);
if (t > 0.00001) { // ray intersection
if (r_res)
*r_res = p_from + p_dir * t;
return true;
} else // this means that there is a line intersection
// but not a ray intersection
} else // This means that there is a line intersection but not a ray intersection.
return false;
}
@ -234,7 +229,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = rel.cross(e2);
real_t a = e1.dot(h);
if (Math::is_zero_approx(a)) // parallel test
if (Math::is_zero_approx(a)) // Parallel test.
return false;
real_t f = 1.0 / a;
@ -252,16 +247,15 @@ public:
if (v < 0.0 || u + v > 1.0)
return false;
// at this stage we can compute t to find out where
// the intersection point is on the line
// At this stage we can compute t to find out where
// the intersection point is on the line.
real_t t = f * e2.dot(q);
if (t > CMP_EPSILON && t <= 1.0) { // ray intersection
if (t > CMP_EPSILON && t <= 1.0) { // Ray intersection.
if (r_res)
*r_res = p_from + rel * t;
return true;
} else // this means that there is a line intersection
// but not a ray intersection
} else // This means that there is a line intersection but not a ray intersection.
return false;
}
@ -271,13 +265,11 @@ public:
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
if (rel_l < CMP_EPSILON)
return false; // both points are the same
return false; // Both points are the same.
Vector3 normal = rel / rel_l;
real_t sphere_d = normal.dot(sphere_pos);
//Vector3 ray_closest=normal*sphere_d;
real_t ray_distance = sphere_pos.distance_to(normal * sphere_d);
if (ray_distance >= p_sphere_radius)
@ -289,7 +281,7 @@ public:
if (inters_d2 >= CMP_EPSILON)
inters_d -= Math::sqrt(inters_d2);
// check in segment
// Check in segment.
if (inters_d < 0 || inters_d > rel_l)
return false;
@ -308,9 +300,9 @@ public:
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
if (rel_l < CMP_EPSILON)
return false; // both points are the same
return false; // Both points are the same.
// first check if they are parallel
// First check if they are parallel.
Vector3 normal = (rel / rel_l);
Vector3 crs = normal.cross(Vector3(0, 0, 1));
real_t crs_l = crs.length();
@ -318,8 +310,7 @@ public:
Vector3 z_dir;
if (crs_l < CMP_EPSILON) {
//blahblah parallel
z_dir = Vector3(1, 0, 0); //any x/y vector ok
z_dir = Vector3(1, 0, 0); // Any x/y vector OK.
} else {
z_dir = crs / crs_l;
}
@ -327,12 +318,12 @@ public:
real_t dist = z_dir.dot(p_from);
if (dist >= p_radius)
return false; // too far away
return false; // Too far away.
// convert to 2D
// Convert to 2D.
real_t w2 = p_radius * p_radius - dist * dist;
if (w2 < CMP_EPSILON)
return false; //avoid numerical error
return false; // Avoid numerical error.
Size2 size(Math::sqrt(w2), p_height * 0.5);
Vector3 x_dir = z_dir.cross(Vector3(0, 0, 1)).normalized();
@ -379,7 +370,7 @@ public:
return false;
}
// convert to 3D again
// Convert to 3D again.
Vector3 result = p_from + (rel * min);
Vector3 res_normal = result;
@ -420,19 +411,18 @@ public:
real_t den = p.normal.dot(dir);
//printf("den is %i\n",den);
if (Math::abs(den) <= CMP_EPSILON)
continue; // ignore parallel plane
continue; // Ignore parallel plane.
real_t dist = -p.distance_to(p_from) / den;
if (den > 0) {
//backwards facing plane
// Backwards facing plane.
if (dist < max)
max = dist;
} else {
//front facing plane
// Front facing plane.
if (dist > min) {
min = dist;
min_index = i;
@ -440,8 +430,8 @@ public:
}
}
if (max <= min || min < 0 || min > rel_l || min_index == -1) // exit conditions
return false; // no intersection
if (max <= min || min < 0 || min > rel_l || min_index == -1) // Exit conditions.
return false; // No intersection.
if (p_res)
*p_res = p_from + dir * min;
@ -457,16 +447,16 @@ public:
Vector3 n = p_segment[1] - p_segment[0];
real_t l2 = n.length_squared();
if (l2 < 1e-20)
return p_segment[0]; // both points are the same, just give any
return p_segment[0]; // Both points are the same, just give any.
real_t d = n.dot(p) / l2;
if (d <= 0.0)
return p_segment[0]; // before first point
return p_segment[0]; // Before first point.
else if (d >= 1.0)
return p_segment[1]; // after first point
return p_segment[1]; // After first point.
else
return p_segment[0] + n * d; // inside
return p_segment[0] + n * d; // Inside.
}
static Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 *p_segment) {
@ -475,11 +465,11 @@ public:
Vector3 n = p_segment[1] - p_segment[0];
real_t l2 = n.length_squared();
if (l2 < 1e-20)
return p_segment[0]; // both points are the same, just give any
return p_segment[0]; // Both points are the same, just give any.
real_t d = n.dot(p) / l2;
return p_segment[0] + n * d; // inside
return p_segment[0] + n * d; // Inside.
}
static Vector2 get_closest_point_to_segment_2d(const Vector2 &p_point, const Vector2 *p_segment) {
@ -488,16 +478,16 @@ public:
Vector2 n = p_segment[1] - p_segment[0];
real_t l2 = n.length_squared();
if (l2 < 1e-20)
return p_segment[0]; // both points are the same, just give any
return p_segment[0]; // Both points are the same, just give any.
real_t d = n.dot(p) / l2;
if (d <= 0.0)
return p_segment[0]; // before first point
return p_segment[0]; // Before first point.
else if (d >= 1.0)
return p_segment[1]; // after first point
return p_segment[1]; // After first point.
else
return p_segment[0] + n * d; // inside
return p_segment[0] + n * d; // Inside.
}
static bool is_point_in_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) {
@ -512,27 +502,25 @@ public:
return (cn.cross(an) > 0) == orientation;
}
//static bool is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon);
static Vector2 get_closest_point_to_segment_uncapped_2d(const Vector2 &p_point, const Vector2 *p_segment) {
Vector2 p = p_point - p_segment[0];
Vector2 n = p_segment[1] - p_segment[0];
real_t l2 = n.length_squared();
if (l2 < 1e-20)
return p_segment[0]; // both points are the same, just give any
return p_segment[0]; // Both points are the same, just give any.
real_t d = n.dot(p) / l2;
return p_segment[0] + n * d; // inside
return p_segment[0] + n * d; // Inside.
}
static bool line_intersects_line_2d(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b, Vector2 &r_result) {
// see http://paulbourke.net/geometry/pointlineplane/
// See http://paulbourke.net/geometry/pointlineplane/
const real_t denom = p_dir_b.y * p_dir_a.x - p_dir_b.x * p_dir_a.y;
if (Math::is_zero_approx(denom)) { // parallel?
if (Math::is_zero_approx(denom)) { // Parallel?
return false;
}
@ -560,11 +548,11 @@ public:
real_t ABpos = D.x + (C.x - D.x) * D.y / (D.y - C.y);
// Fail if segment C-D crosses line A-B outside of segment A-B.
// Fail if segment C-D crosses line A-B outside of segment A-B.
if (ABpos < 0 || ABpos > 1.0)
return false;
// (4) Apply the discovered position to line A-B in the original coordinate system.
// (4) Apply the discovered position to line A-B in the original coordinate system.
if (r_result)
*r_result = p_from_a + B * ABpos;
@ -597,7 +585,7 @@ public:
real_t d = p_normal.dot(p_sphere_pos) - p_normal.dot(p_triangle[0]);
if (d > p_sphere_radius || d < -p_sphere_radius) // not touching the plane of the face, return
if (d > p_sphere_radius || d < -p_sphere_radius) // Not touching the plane of the face, return.
return false;
Vector3 contact = p_sphere_pos - (p_normal * d);
@ -617,25 +605,25 @@ public:
for (int i = 0; i < 3; i++) {
// check edge cylinder
// Check edge cylinder.
Vector3 n1 = verts[i] - verts[i + 1];
Vector3 n2 = p_sphere_pos - verts[i + 1];
///@TODO i could discard by range here to make the algorithm quicker? dunno..
///@TODO Maybe discard by range here to make the algorithm quicker.
// check point within cylinder radius
// Check point within cylinder radius.
Vector3 axis = n1.cross(n2).cross(n1);
axis.normalize(); // ugh
axis.normalize();
real_t ad = axis.dot(n2);
if (ABS(ad) > p_sphere_radius) {
// no chance with this edge, too far away
// No chance with this edge, too far away.
continue;
}
// check point within edge capsule cylinder
// Check point within edge capsule cylinder.
/** 4th TEST INSIDE EDGE POINTS **/
real_t sphere_at = n1.dot(n2);
@ -644,8 +632,7 @@ public:
r_triangle_contact = p_sphere_pos - axis * (axis.dot(n2));
r_sphere_contact = p_sphere_pos - axis * p_sphere_radius;
// point inside here
//printf("solved inside edge\n");
// Point inside here.
return true;
}
@ -655,48 +642,51 @@ public:
Vector3 n = (p_sphere_pos - verts[i + 1]).normalized();
//r_triangle_contact=verts[i+1]+n*p_sphere_radius;p_sphere_pos+axis*(p_sphere_radius-axis.dot(n2));
r_triangle_contact = verts[i + 1];
r_sphere_contact = p_sphere_pos - n * p_sphere_radius;
//printf("solved inside point segment 1\n");
return true;
}
if (n2.distance_squared_to(n1) < r2) {
Vector3 n = (p_sphere_pos - verts[i]).normalized();
//r_triangle_contact=verts[i]+n*p_sphere_radius;p_sphere_pos+axis*(p_sphere_radius-axis.dot(n2));
r_triangle_contact = verts[i];
r_sphere_contact = p_sphere_pos - n * p_sphere_radius;
//printf("solved inside point segment 1\n");
return true;
}
break; // It's pointless to continue at this point, so save some cpu cycles
break; // It's pointless to continue at this point, so save some CPU cycles.
}
return false;
}
static inline bool is_point_in_circle(const Vector2 &p_point, const Vector2 &p_circle_pos, real_t p_circle_radius) {
return p_point.distance_squared_to(p_circle_pos) <= p_circle_radius * p_circle_radius;
}
static real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius) {
Vector2 line_vec = p_to - p_from;
Vector2 vec_to_line = p_from - p_circle_pos;
/* create a quadratic formula of the form ax^2 + bx + c = 0 */
// Create a quadratic formula of the form ax^2 + bx + c = 0
real_t a, b, c;
a = line_vec.dot(line_vec);
b = 2 * vec_to_line.dot(line_vec);
c = vec_to_line.dot(vec_to_line) - p_circle_radius * p_circle_radius;
/* solve for t */
// Solve for t.
real_t sqrtterm = b * b - 4 * a * c;
/* if the term we intend to square root is less than 0 then the answer won't be real, so it definitely won't be t in the range 0 to 1 */
// If the term we intend to square root is less than 0 then the answer won't be real,
// so it definitely won't be t in the range 0 to 1.
if (sqrtterm < 0) return -1;
/* if we can assume that the line segment starts outside the circle (e.g. for continuous time collision detection) then the following can be skipped and we can just return the equivalent of res1 */
// If we can assume that the line segment starts outside the circle (e.g. for continuous time collision detection)
// then the following can be skipped and we can just return the equivalent of res1.
sqrtterm = Math::sqrt(sqrtterm);
real_t res1 = (-b - sqrtterm) / (2 * a);
real_t res2 = (-b + sqrtterm) / (2 * a);
@ -722,7 +712,6 @@ public:
int outside_count = 0;
for (int a = 0; a < polygon.size(); a++) {
//real_t p_plane.d = (*this) * polygon[a];
real_t dist = p_plane.distance_to(polygon[a]);
if (dist < -CMP_POINT_IN_PLANE_EPSILON) {
location_cache[a] = LOC_INSIDE;
@ -739,11 +728,11 @@ public:
if (outside_count == 0) {
return polygon; // no changes
return polygon; // No changes.
} else if (inside_count == 0) {
return Vector<Vector3>(); //empty
return Vector<Vector3>(); // Empty.
}
long previous = polygon.size() - 1;
@ -838,22 +827,11 @@ public:
static Vector<Vector<Point2> > offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
ERR_EXPLAIN("Attempt to offset a polyline like a polygon (use offset_polygon_2d instead).");
ERR_FAIL_COND_V(p_end_type == END_POLYGON, Vector<Vector<Point2> >());
ERR_FAIL_COND_V_MSG(p_end_type == END_POLYGON, Vector<Vector<Point2> >(), "Attempt to offset a polyline like a polygon (use offset_polygon_2d instead).");
return _polypath_offset(p_polygon, p_delta, p_join_type, p_end_type);
}
static Vector<Point2> transform_points_2d(const Vector<Point2> &p_points, const Transform2D &p_mat) {
Vector<Point2> points;
for (int i = 0; i < p_points.size(); ++i) {
points.push_back(p_mat.xform(p_points[i]));
}
return points;
}
static Vector<int> triangulate_delaunay_2d(const Vector<Vector2> &p_points) {
Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(p_points);
@ -899,7 +877,7 @@ public:
return sum > 0.0f;
}
/* alternate implementation that should be faster */
// Alternate implementation that should be faster.
static bool is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) {
int c = p_polygon.size();
if (c < 3)
@ -915,7 +893,8 @@ public:
further_away_opposite.y = MIN(p[i].y, further_away_opposite.y);
}
further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312); // make point outside that won't intersect with points in segment from p_point
// Make point outside that won't intersect with points in segment from p_point.
further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312);
int intersections = 0;
for (int i = 0; i < c; i++) {
@ -931,7 +910,8 @@ public:
static PoolVector<PoolVector<Face3> > separate_objects(PoolVector<Face3> p_array);
static PoolVector<Face3> wrap_geometry(PoolVector<Face3> p_array, real_t *p_error = NULL); ///< create a "wrap" that encloses the given geometry
// Create a "wrap" that encloses the given geometry.
static PoolVector<Face3> wrap_geometry(PoolVector<Face3> p_array, real_t *p_error = NULL);
struct MeshData {
@ -1013,17 +993,17 @@ public:
Vector<Point2> H;
H.resize(2 * n);
// Sort points lexicographically
// Sort points lexicographically.
P.sort();
// Build lower hull
// Build lower hull.
for (int i = 0; i < n; ++i) {
while (k >= 2 && vec2_cross(H[k - 2], H[k - 1], P[i]) <= 0)
k--;
H.write[k++] = P[i];
}
// Build upper hull
// Build upper hull.
for (int i = n - 2, t = k + 1; i >= 0; i--) {
while (k >= t && vec2_cross(H[k - 2], H[k - 1], P[i]) <= 0)
k--;

View file

@ -79,6 +79,15 @@ int Math::step_decimals(double p_step) {
return 0;
}
// Only meant for editor usage in float ranges, where a step of 0
// means that decimal digits should not be limited in String::num.
int Math::range_step_decimals(double p_step) {
if (p_step < 0.0000000000001) {
return 16; // Max value hardcoded in String::num
}
return step_decimals(p_step);
}
double Math::dectime(double p_value, double p_amount, double p_step) {
double sgn = p_value < 0 ? -1.0 : 1.0;
double val = Math::abs(p_value);

View file

@ -255,21 +255,22 @@ public:
static _ALWAYS_INLINE_ float round(float p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); }
static _ALWAYS_INLINE_ int64_t wrapi(int64_t value, int64_t min, int64_t max) {
int64_t rng = max - min;
return (rng != 0) ? min + ((((value - min) % rng) + rng) % rng) : min;
int64_t range = max - min;
return range == 0 ? min : min + ((((value - min) % range) + range) % range);
}
static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) {
double rng = max - min;
return (!is_equal_approx(rng, 0.0)) ? value - (rng * Math::floor((value - min) / rng)) : min;
double range = max - min;
return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range));
}
static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) {
float rng = max - min;
return (!is_equal_approx(rng, 0.0f)) ? value - (rng * Math::floor((value - min) / rng)) : min;
float range = max - min;
return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range));
}
// double only, as these functions are mainly used by the editor and not performance-critical,
static double ease(double p_x, double p_c);
static int step_decimals(double p_step);
static int range_step_decimals(double p_step);
static double stepify(double p_value, double p_step);
static double dectime(double p_value, double p_amount, double p_step);
@ -299,6 +300,11 @@ public:
}
static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
real_t tolerance = CMP_EPSILON * abs(a);
if (tolerance < CMP_EPSILON) {
tolerance = CMP_EPSILON;
@ -307,6 +313,11 @@ public:
}
static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t tolerance) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
return abs(a - b) < tolerance;
}

View file

@ -38,10 +38,6 @@
#include "core/print_string.h"
#include "core/variant.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
typedef uint32_t OctreeElementID;
#define OCTREE_ELEMENT_INVALID_ID 0
@ -568,10 +564,7 @@ void Octree<T, use_pairs, AL>::_ensure_valid_root(const AABB &p_aabb) {
while (!base.encloses(p_aabb)) {
if (base.size.x > OCTREE_SIZE_LIMIT) {
ERR_EXPLAIN("Octree upper size limit reeached, does the AABB supplied contain NAN?");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(base.size.x > OCTREE_SIZE_LIMIT, "Octree upper size limit reached, does the AABB supplied contain NAN?");
Octant *gp = memnew_allocator(Octant, AL);
octant_count++;

View file

@ -38,10 +38,6 @@
#include "core/math/math_funcs.h"
#include "core/ustring.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class Quat {
public:
real_t x, y, z, w;

View file

@ -213,3 +213,8 @@ Transform::Transform(const Basis &p_basis, const Vector3 &p_origin) :
basis(p_basis),
origin(p_origin) {
}
Transform::Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) {
basis = Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz);
origin = Vector3(ox, oy, oz);
}

View file

@ -34,10 +34,7 @@
#include "core/math/aabb.h"
#include "core/math/basis.h"
#include "core/math/plane.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
#include "core/pool_vector.h"
class Transform {
public:
@ -86,6 +83,9 @@ public:
_FORCE_INLINE_ AABB xform(const AABB &p_aabb) const;
_FORCE_INLINE_ AABB xform_inv(const AABB &p_aabb) const;
_FORCE_INLINE_ PoolVector<Vector3> xform(const PoolVector<Vector3> &p_array) const;
_FORCE_INLINE_ PoolVector<Vector3> xform_inv(const PoolVector<Vector3> &p_array) const;
void operator*=(const Transform &p_transform);
Transform operator*(const Transform &p_transform) const;
@ -108,6 +108,7 @@ public:
operator String() const;
Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz);
Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3());
Transform() {}
};
@ -157,22 +158,29 @@ _FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const {
}
_FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const {
/* define vertices */
Vector3 x = basis.get_axis(0) * p_aabb.size.x;
Vector3 y = basis.get_axis(1) * p_aabb.size.y;
Vector3 z = basis.get_axis(2) * p_aabb.size.z;
Vector3 pos = xform(p_aabb.position);
//could be even further optimized
AABB new_aabb;
new_aabb.position = pos;
new_aabb.expand_to(pos + x);
new_aabb.expand_to(pos + y);
new_aabb.expand_to(pos + z);
new_aabb.expand_to(pos + x + y);
new_aabb.expand_to(pos + x + z);
new_aabb.expand_to(pos + y + z);
new_aabb.expand_to(pos + x + y + z);
return new_aabb;
/* http://dev.theomader.com/transform-bounding-boxes/ */
Vector3 min = p_aabb.position;
Vector3 max = p_aabb.position + p_aabb.size;
Vector3 tmin, tmax;
for (int i = 0; i < 3; i++) {
tmin[i] = tmax[i] = origin[i];
for (int j = 0; j < 3; j++) {
real_t e = basis[i][j] * min[j];
real_t f = basis[i][j] * max[j];
if (e < f) {
tmin[i] += e;
tmax[i] += f;
} else {
tmin[i] += f;
tmax[i] += e;
}
}
}
AABB r_aabb;
r_aabb.position = tmin;
r_aabb.size = tmax - tmin;
return r_aabb;
}
_FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const {
@ -201,4 +209,32 @@ _FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const {
return ret;
}
PoolVector<Vector3> Transform::xform(const PoolVector<Vector3> &p_array) const {
PoolVector<Vector3> array;
array.resize(p_array.size());
PoolVector<Vector3>::Read r = p_array.read();
PoolVector<Vector3>::Write w = array.write();
for (int i = 0; i < p_array.size(); ++i) {
w[i] = xform(r[i]);
}
return array;
}
PoolVector<Vector3> Transform::xform_inv(const PoolVector<Vector3> &p_array) const {
PoolVector<Vector3> array;
array.resize(p_array.size());
PoolVector<Vector3>::Read r = p_array.read();
PoolVector<Vector3>::Write w = array.write();
for (int i = 0; i < p_array.size(); ++i) {
w[i] = xform_inv(r[i]);
}
return array;
}
#endif // TRANSFORM_H

View file

@ -32,6 +32,7 @@
#define TRANSFORM_2D_H
#include "core/math/rect2.h" // also includes vector2, math_funcs, and ustring
#include "core/pool_vector.h"
struct Transform2D {
// Warning #1: basis of Transform2D is stored differently from Basis. In terms of elements array, the basis matrix looks like "on paper":
@ -110,6 +111,8 @@ struct Transform2D {
_FORCE_INLINE_ Vector2 xform_inv(const Vector2 &p_vec) const;
_FORCE_INLINE_ Rect2 xform(const Rect2 &p_rect) const;
_FORCE_INLINE_ Rect2 xform_inv(const Rect2 &p_rect) const;
_FORCE_INLINE_ PoolVector<Vector2> xform(const PoolVector<Vector2> &p_array) const;
_FORCE_INLINE_ PoolVector<Vector2> xform_inv(const PoolVector<Vector2> &p_array) const;
operator String() const;
@ -199,4 +202,32 @@ Rect2 Transform2D::xform_inv(const Rect2 &p_rect) const {
return new_rect;
}
PoolVector<Vector2> Transform2D::xform(const PoolVector<Vector2> &p_array) const {
PoolVector<Vector2> array;
array.resize(p_array.size());
PoolVector<Vector2>::Read r = p_array.read();
PoolVector<Vector2>::Write w = array.write();
for (int i = 0; i < p_array.size(); ++i) {
w[i] = xform(r[i]);
}
return array;
}
PoolVector<Vector2> Transform2D::xform_inv(const PoolVector<Vector2> &p_array) const {
PoolVector<Vector2> array;
array.resize(p_array.size());
PoolVector<Vector2>::Read r = p_array.read();
PoolVector<Vector2>::Write w = array.write();
for (int i = 0; i < p_array.size(); ++i) {
w[i] = xform_inv(r[i]);
}
return array;
}
#endif // TRANSFORM_2D_H

View file

@ -98,6 +98,11 @@ real_t Vector2::cross(const Vector2 &p_other) const {
return x * p_other.y - y * p_other.x;
}
Vector2 Vector2::sign() const {
return Vector2(SGN(x), SGN(y));
}
Vector2 Vector2::floor() const {
return Vector2(Math::floor(x), Math::floor(y));
@ -121,6 +126,14 @@ Vector2 Vector2::rotated(real_t p_by) const {
return v;
}
Vector2 Vector2::posmod(const real_t p_mod) const {
return Vector2(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod));
}
Vector2 Vector2::posmodv(const Vector2 &p_modv) const {
return Vector2(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y));
}
Vector2 Vector2::project(const Vector2 &p_b) const {
return p_b * (dot(p_b) / p_b.length_squared());
}

View file

@ -38,6 +38,11 @@ struct Vector2i;
struct Vector2 {
enum Axis {
AXIS_X,
AXIS_Y,
};
union {
real_t x;
real_t width;
@ -69,6 +74,8 @@ struct Vector2 {
real_t dot(const Vector2 &p_other) const;
real_t cross(const Vector2 &p_other) const;
Vector2 posmod(const real_t p_mod) const;
Vector2 posmodv(const Vector2 &p_modv) const;
Vector2 project(const Vector2 &p_b) const;
Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const;
@ -107,8 +114,10 @@ struct Vector2 {
bool operator==(const Vector2 &p_vec2) const;
bool operator!=(const Vector2 &p_vec2) const;
bool operator<(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y < p_vec2.y) : (x < p_vec2.x); }
bool operator<=(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y <= p_vec2.y) : (x < p_vec2.x); }
bool operator<(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
bool operator>(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); }
bool operator<=(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y <= p_vec2.y) : (x < p_vec2.x); }
bool operator>=(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y >= p_vec2.y) : (x > p_vec2.x); }
real_t angle() const;
@ -129,6 +138,7 @@ struct Vector2 {
return Vector2(y, -x);
}
Vector2 sign() const;
Vector2 floor() const;
Vector2 ceil() const;
Vector2 round() const;
@ -141,10 +151,7 @@ struct Vector2 {
x = p_x;
y = p_y;
}
_FORCE_INLINE_ Vector2() {
x = 0;
y = 0;
}
_FORCE_INLINE_ Vector2() { x = y = 0; }
};
_FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const {
@ -262,6 +269,11 @@ typedef Vector2 Point2;
struct Vector2i {
enum Axis {
AXIS_X,
AXIS_Y,
};
union {
int x;
int width;

View file

@ -31,9 +31,7 @@
#ifndef VECTOR3_H
#define VECTOR3_H
#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
#include "core/typedefs.h"
#include "core/ustring.h"
class Basis;
@ -110,6 +108,8 @@ struct Vector3 {
_FORCE_INLINE_ real_t distance_to(const Vector3 &p_b) const;
_FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_b) const;
_FORCE_INLINE_ Vector3 posmod(const real_t p_mod) const;
_FORCE_INLINE_ Vector3 posmodv(const Vector3 &p_modv) const;
_FORCE_INLINE_ Vector3 project(const Vector3 &p_b) const;
_FORCE_INLINE_ real_t angle_to(const Vector3 &p_b) const;
@ -141,15 +141,17 @@ struct Vector3 {
_FORCE_INLINE_ bool operator!=(const Vector3 &p_v) const;
_FORCE_INLINE_ bool operator<(const Vector3 &p_v) const;
_FORCE_INLINE_ bool operator<=(const Vector3 &p_v) const;
_FORCE_INLINE_ bool operator>(const Vector3 &p_v) const;
_FORCE_INLINE_ bool operator>=(const Vector3 &p_v) const;
operator String() const;
_FORCE_INLINE_ Vector3() { x = y = z = 0; }
_FORCE_INLINE_ Vector3(real_t p_x, real_t p_y, real_t p_z) {
x = p_x;
y = p_y;
z = p_z;
}
_FORCE_INLINE_ Vector3() { x = y = z = 0; }
};
// Should be included after class definition, otherwise we get circular refs
@ -233,6 +235,14 @@ real_t Vector3::distance_squared_to(const Vector3 &p_b) const {
return (p_b - *this).length_squared();
}
Vector3 Vector3::posmod(const real_t p_mod) const {
return Vector3(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod));
}
Vector3 Vector3::posmodv(const Vector3 &p_modv) const {
return Vector3(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z));
}
Vector3 Vector3::project(const Vector3 &p_b) const {
return p_b * (dot(p_b) / p_b.length_squared());
}
@ -357,6 +367,18 @@ bool Vector3::operator<(const Vector3 &p_v) const {
}
}
bool Vector3::operator>(const Vector3 &p_v) const {
if (Math::is_equal_approx(x, p_v.x)) {
if (Math::is_equal_approx(y, p_v.y))
return z > p_v.z;
else
return y > p_v.y;
} else {
return x > p_v.x;
}
}
bool Vector3::operator<=(const Vector3 &p_v) const {
if (Math::is_equal_approx(x, p_v.x)) {
@ -369,6 +391,18 @@ bool Vector3::operator<=(const Vector3 &p_v) const {
}
}
bool Vector3::operator>=(const Vector3 &p_v) const {
if (Math::is_equal_approx(x, p_v.x)) {
if (Math::is_equal_approx(y, p_v.y))
return z >= p_v.z;
else
return y > p_v.y;
} else {
return x > p_v.x;
}
}
_FORCE_INLINE_ Vector3 vec3_cross(const Vector3 &p_a, const Vector3 &p_b) {
return p_a.cross(p_b);

View file

@ -52,8 +52,7 @@ Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, const V
type = ObjectDB::get_instance(p_id)->get_class();
print_line("Failed method: " + type + ":" + p_method + " target ID: " + itos(p_id));
statistics();
ERR_EXPLAIN("Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings.");
ERR_FAIL_V(ERR_OUT_OF_MEMORY);
ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings.");
}
Message *msg = memnew_placement(&buffer[buffer_end], Message);
@ -103,8 +102,7 @@ Error MessageQueue::push_set(ObjectID p_id, const StringName &p_prop, const Vari
type = ObjectDB::get_instance(p_id)->get_class();
print_line("Failed set: " + type + ":" + p_prop + " target ID: " + itos(p_id));
statistics();
ERR_EXPLAIN("Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings.");
ERR_FAIL_V(ERR_OUT_OF_MEMORY);
ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings.");
}
Message *msg = memnew_placement(&buffer[buffer_end], Message);
@ -136,8 +134,7 @@ Error MessageQueue::push_notification(ObjectID p_id, int p_notification) {
type = ObjectDB::get_instance(p_id)->get_class();
print_line("Failed notification: " + itos(p_notification) + " target ID: " + itos(p_id));
statistics();
ERR_EXPLAIN("Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings.");
ERR_FAIL_V(ERR_OUT_OF_MEMORY);
ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings.");
}
Message *msg = memnew_placement(&buffer[buffer_end], Message);
@ -256,7 +253,7 @@ void MessageQueue::_call_function(Object *p_target, const StringName &p_func, co
p_target->call(p_func, argptrs, p_argcount, ce);
if (p_show_error && ce.error != Variant::CallError::CALL_OK) {
ERR_PRINTS("Error calling deferred method: " + Variant::get_call_error_text(p_target, p_func, argptrs, p_argcount, ce));
ERR_PRINTS("Error calling deferred method: " + Variant::get_call_error_text(p_target, p_func, argptrs, p_argcount, ce) + ".");
}
}

View file

@ -38,10 +38,6 @@
#include <stdio.h>
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
#ifdef DEBUG_ENABLED
#define DEBUG_METHODS_ENABLED
#endif

View file

@ -375,8 +375,7 @@ NodePath::NodePath(const String &p_path) {
if (str == "") {
if (path[i] == 0) continue; // Allow end-of-path :
ERR_EXPLAIN("Invalid NodePath: " + p_path);
ERR_FAIL();
ERR_FAIL_MSG("Invalid NodePath: " + p_path + ".");
}
subpath.push_back(str);

View file

@ -34,10 +34,6 @@
#include "core/string_name.h"
#include "core/ustring.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class NodePath {
struct Data {

View file

@ -62,7 +62,7 @@ private:
static const uint32_t EMPTY_HASH = 0;
static const uint32_t DELETED_HASH_BIT = 1 << 31;
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) {
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
uint32_t hash = Hasher::hash(p_key);
if (hash == EMPTY_HASH) {
@ -74,12 +74,11 @@ private:
return hash;
}
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash) {
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash) const {
p_hash = p_hash & ~DELETED_HASH_BIT; // we don't care if it was deleted or not
uint32_t original_pos = p_hash % capacity;
return p_pos - original_pos;
return (p_pos - original_pos) % capacity;
}
_FORCE_INLINE_ void _construct(uint32_t p_pos, uint32_t p_hash, const TKey &p_key, const TValue &p_value) {
@ -90,7 +89,7 @@ private:
num_elements++;
}
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) {
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
uint32_t hash = _hash(p_key);
uint32_t pos = hash % capacity;
uint32_t distance = 0;
@ -151,17 +150,17 @@ private:
distance++;
}
}
void _resize_and_rehash() {
void _resize_and_rehash(uint32_t p_new_capacity) {
uint32_t old_capacity = capacity;
capacity = p_new_capacity;
TKey *old_keys = keys;
TValue *old_values = values;
uint32_t *old_hashes = hashes;
uint32_t old_capacity = capacity;
capacity = old_capacity * 2;
num_elements = 0;
keys = memnew_arr(TKey, capacity);
values = memnew_arr(TValue, capacity);
hashes = memnew_arr(uint32_t, capacity);
@ -186,10 +185,38 @@ private:
memdelete_arr(old_hashes);
}
void _resize_and_rehash() {
_resize_and_rehash(capacity * 2);
}
public:
_FORCE_INLINE_ uint32_t get_capacity() const { return capacity; }
_FORCE_INLINE_ uint32_t get_num_elements() const { return num_elements; }
bool empty() const {
return num_elements == 0;
}
void clear() {
for (uint32_t i = 0; i < capacity; i++) {
if (hashes[i] == EMPTY_HASH) {
continue;
}
if (hashes[i] & DELETED_HASH_BIT) {
continue;
}
hashes[i] = EMPTY_HASH;
values[i].~TValue();
keys[i].~TKey();
}
num_elements = 0;
}
void insert(const TKey &p_key, const TValue &p_value) {
if ((float)num_elements / (float)capacity > 0.9) {
@ -219,7 +246,7 @@ public:
* if r_data is not NULL then the value will be written to the object
* it points to.
*/
bool lookup(const TKey &p_key, TValue &r_data) {
bool lookup(const TKey &p_key, TValue &r_data) const {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
@ -232,7 +259,7 @@ public:
return false;
}
_FORCE_INLINE_ bool has(const TKey &p_key) {
_FORCE_INLINE_ bool has(const TKey &p_key) const {
uint32_t _pos = 0;
return _lookup_pos(p_key, _pos);
}
@ -251,6 +278,16 @@ public:
num_elements--;
}
/**
* reserves space for a number of elements, useful to avoid many resizes and rehashes
* if adding a known (possibly large) number of elements at once, must be larger than old
* capacity.
**/
void reserve(uint32_t p_new_capacity) {
ERR_FAIL_COND(p_new_capacity < capacity);
_resize_and_rehash(p_new_capacity);
}
struct Iterator {
bool valid;
@ -302,6 +339,9 @@ public:
return it;
}
OAHashMap(const OAHashMap &) = delete; // Delete the copy constructor so we don't get unexpected copies and dangling pointers.
OAHashMap &operator=(const OAHashMap &) = delete; // Same for assignment operator.
OAHashMap(uint32_t p_initial_capacity = 64) {
capacity = p_initial_capacity;
@ -312,7 +352,7 @@ public:
hashes = memnew_arr(uint32_t, p_initial_capacity);
for (uint32_t i = 0; i < p_initial_capacity; i++) {
hashes[i] = 0;
hashes[i] = EMPTY_HASH;
}
}

View file

@ -635,12 +635,9 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
#endif
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
#ifdef TOOLS_ENABLED
p_list->push_back(PropertyInfo(Variant::NIL, "Metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
#endif
p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
if (!metadata.empty()) {
p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
if (script_instance && !p_reversed) {
p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
@ -712,20 +709,17 @@ static void _test_call_error(const StringName &p_func, const Variant::CallError
break;
case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT: {
ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(error.expected));
ERR_FAIL();
ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(error.expected) + ".");
break;
}
case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: {
ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument));
ERR_FAIL();
ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument) + ".");
break;
}
case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: {
ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument));
ERR_FAIL();
ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument) + ".");
break;
}
case Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL:
@ -742,15 +736,9 @@ void Object::call_multilevel(const StringName &p_method, const Variant **p_args,
if (p_method == CoreStringNames::get_singleton()->_free) {
#ifdef DEBUG_ENABLED
if (Object::cast_to<Reference>(this)) {
ERR_EXPLAIN("Can't 'free' a reference.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(Object::cast_to<Reference>(this), "Can't 'free' a reference.");
if (_lock_index.get() > 1) {
ERR_EXPLAIN("Object is locked and can't be freed.");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(_lock_index.get() > 1, "Object is locked and can't be freed.");
#endif
//must be here, must be before everything,
@ -838,8 +826,7 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) {
Variant::CallError ce;
Variant ret = call(p_method, argptrs, p_args.size(), ce);
if (ce.error != Variant::CallError::CALL_OK) {
ERR_EXPLAIN("Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce));
ERR_FAIL_V(Variant());
ERR_FAIL_V_MSG(Variant(), "Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce) + ".");
}
return ret;
}
@ -891,15 +878,13 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a
if (Object::cast_to<Reference>(this)) {
r_error.argument = 0;
r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
ERR_EXPLAIN("Can't 'free' a reference.");
ERR_FAIL_V(Variant());
ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference.");
}
if (_lock_index.get() > 1) {
r_error.argument = 0;
r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
ERR_EXPLAIN("Object is locked and can't be freed.");
ERR_FAIL_V(Variant());
ERR_FAIL_V_MSG(Variant(), "Object is locked and can't be freed.");
}
#endif
@ -1175,10 +1160,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
#ifdef DEBUG_ENABLED
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_name);
//check in script
if (!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name)) {
ERR_EXPLAIN("Can't emit non-existing signal " + String("\"") + p_name + "\".");
ERR_FAIL_V(ERR_UNAVAILABLE);
}
ERR_FAIL_COND_V_MSG(!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name), ERR_UNAVAILABLE, "Can't emit non-existing signal " + String("\"") + p_name + "\".");
#endif
//not connected? just return
return ERR_UNAVAILABLE;
@ -1243,7 +1225,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
if (ce.error == Variant::CallError::CALL_ERROR_INVALID_METHOD && !ClassDB::class_exists(target->get_class_name())) {
//most likely object is not initialized yet, do not throw error.
} else {
ERR_PRINTS("Error calling method from signal '" + String(p_name) + "': " + Variant::get_call_error_text(target, c.method, args, argc, ce));
ERR_PRINTS("Error calling method from signal '" + String(p_name) + "': " + Variant::get_call_error_text(target, c.method, args, argc, ce) + ".");
err = ERR_METHOD_NOT_FOUND;
}
}
@ -1418,8 +1400,9 @@ void Object::get_signal_connection_list(const StringName &p_signal, List<Connect
p_connections->push_back(s->slot_map.getv(i).conn);
}
bool Object::has_persistent_signal_connections() const {
int Object::get_persistent_signal_connection_count() const {
int count = 0;
const StringName *S = NULL;
while ((S = signal_map.next(S))) {
@ -1427,13 +1410,13 @@ bool Object::has_persistent_signal_connections() const {
const Signal *s = &signal_map[*S];
for (int i = 0; i < s->slot_map.size(); i++) {
if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST)
return true;
if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST) {
count += 1;
}
}
}
return false;
return count;
}
void Object::get_signals_connected_to_this(List<Connection> *p_connections) const {
@ -1466,10 +1449,8 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str
#endif
}
if (!signal_is_valid) {
ERR_EXPLAIN("In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_class() + "." + p_to_method + "'");
ERR_FAIL_V(ERR_INVALID_PARAMETER);
}
ERR_FAIL_COND_V_MSG(!signal_is_valid, ERR_INVALID_PARAMETER, "In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_class() + "." + p_to_method + "'.");
signal_map[p_signal] = Signal();
s = &signal_map[p_signal];
}
@ -1480,8 +1461,7 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str
s->slot_map[target].reference_count++;
return OK;
} else {
ERR_EXPLAIN("Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object.");
ERR_FAIL_V(ERR_INVALID_PARAMETER);
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object.");
}
}
@ -1517,8 +1497,7 @@ bool Object::is_connected(const StringName &p_signal, Object *p_to_object, const
if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal))
return false;
ERR_EXPLAIN("Nonexistent signal: " + p_signal);
ERR_FAIL_V(false);
ERR_FAIL_V_MSG(false, "Nonexistent signal: " + p_signal + ".");
}
Signal::Target target(p_to_object->get_instance_id(), p_to_method);
@ -1536,21 +1515,13 @@ void Object::_disconnect(const StringName &p_signal, Object *p_to_object, const
ERR_FAIL_NULL(p_to_object);
Signal *s = signal_map.getptr(p_signal);
if (!s) {
ERR_EXPLAIN("Nonexistent signal: " + p_signal);
ERR_FAIL();
}
if (s->lock > 0) {
ERR_EXPLAIN("Attempt to disconnect signal '" + p_signal + "' while emitting (locks: " + itos(s->lock) + ")");
ERR_FAIL();
}
ERR_FAIL_COND_MSG(!s, "Nonexistent signal: " + p_signal + ".");
ERR_FAIL_COND_MSG(s->lock > 0, "Attempt to disconnect signal '" + p_signal + "' while emitting (locks: " + itos(s->lock) + ").");
Signal::Target target(p_to_object->get_instance_id(), p_to_method);
if (!s->slot_map.has(target)) {
ERR_EXPLAIN("Disconnecting nonexistent signal '" + p_signal + "', slot: " + itos(target._id) + ":" + target.method);
ERR_FAIL();
}
ERR_FAIL_COND_MSG(!s->slot_map.has(target), "Disconnecting nonexistent signal '" + p_signal + "', slot: " + itos(target._id) + ":" + target.method + ".");
Signal::Slot *slot = &s->slot_map[target];
@ -1977,10 +1948,7 @@ Object::~Object() {
Signal *s = &signal_map[*S];
if (s->lock) {
ERR_EXPLAIN("Attempt to delete an object in the middle of a signal emission from it");
ERR_CONTINUE(s->lock > 0);
}
ERR_CONTINUE_MSG(s->lock > 0, "Attempt to delete an object in the middle of a signal emission from it.");
//brute force disconnect for performance
int slot_count = s->slot_map.size();

View file

@ -58,7 +58,7 @@ enum PropertyHint {
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
PROPERTY_HINT_SPRITE_FRAME,
PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat. Keeping now for GDNative compat.
PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
PROPERTY_HINT_LAYERS_2D_RENDER,
@ -104,7 +104,8 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings
PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor
PROPERTY_USAGE_CATEGORY = 256,
//those below are deprecated thanks to ClassDB's now class value cache
// FIXME: Drop in 4.0, possibly reorder other flags?
// Those below are deprecated thanks to ClassDB's now class value cache
//PROPERTY_USAGE_STORE_IF_NONZERO = 512, //only store if nonzero
//PROPERTY_USAGE_STORE_IF_NONONE = 1024, //only store if false
PROPERTY_USAGE_NO_INSTANCE_STATE = 2048,
@ -121,6 +122,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_HIGH_END_GFX = 1 << 22,
PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 23,
PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 24,
PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK,
PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED,
@ -705,7 +707,7 @@ public:
void get_signal_list(List<MethodInfo> *p_signals) const;
void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
void get_all_signal_connections(List<Connection> *p_connections) const;
bool has_persistent_signal_connections() const;
int get_persistent_signal_connection_count() const;
void get_signals_connected_to_this(List<Connection> *p_connections) const;
Error connect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0);
@ -792,8 +794,13 @@ public:
static int get_object_count();
_FORCE_INLINE_ static bool instance_validate(Object *p_ptr) {
rw_lock->read_lock();
return instance_checks.has(p_ptr);
bool exists = instance_checks.has(p_ptr);
rw_lock->read_unlock();
return exists;
}
};

View file

@ -179,14 +179,6 @@ Error DirAccess::make_dir_recursive(String p_dir) {
return OK;
}
String DirAccess::get_next(bool *p_is_dir) {
String next = get_next();
if (p_is_dir)
*p_is_dir = current_is_dir();
return next;
}
String DirAccess::fix_path(String p_path) const {
switch (_access_type) {

View file

@ -34,10 +34,6 @@
#include "core/typedefs.h"
#include "core/ustring.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
//@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies
class DirAccess {
public:
@ -71,7 +67,6 @@ protected:
public:
virtual Error list_dir_begin() = 0; ///< This starts dir listing
virtual String get_next(bool *p_is_dir); // compatibility
virtual String get_next() = 0;
virtual bool current_is_dir() const = 0;
virtual bool current_is_hidden() const = 0;
@ -98,6 +93,18 @@ public:
virtual Error rename(String p_from, String p_to) = 0;
virtual Error remove(String p_name) = 0;
// Meant for editor code when we want to quickly remove a file without custom
// handling (e.g. removing a cache file).
static void remove_file_or_error(String p_path) {
DirAccess *da = create(ACCESS_FILESYSTEM);
if (da->file_exists(p_path)) {
if (da->remove(p_path) != OK) {
ERR_FAIL_MSG("Cannot remove file or directory: " + p_path);
}
}
memdelete(da);
}
virtual String get_filesystem_type() const = 0;
static String get_full_path(const String &p_path, AccessType p_access);
static DirAccess *create_for_path(const String &p_path);

View file

@ -30,9 +30,9 @@
#include "file_access.h"
#include "core/crypto/crypto_core.h"
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
#include "core/math/crypto_core.h"
#include "core/os/os.h"
#include "core/project_settings.h"
@ -599,8 +599,7 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err
if (r_error) { // if error requested, do not throw error
return Vector<uint8_t>();
}
ERR_EXPLAIN("Can't open file from path: " + String(p_path));
ERR_FAIL_V(Vector<uint8_t>());
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Can't open file from path: " + String(p_path) + ".");
}
Vector<uint8_t> data;
data.resize(f->get_len());
@ -620,8 +619,7 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) {
if (r_error) {
return String();
}
ERR_EXPLAIN("Can't get file as string from path: " + String(p_path));
ERR_FAIL_V(String());
ERR_FAIL_V_MSG(String(), "Can't get file as string from path: " + String(p_path) + ".");
}
String ret;

View file

@ -80,6 +80,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_joy_axis_index_from_string", "axis"), &Input::get_joy_axis_index_from_string);
ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::vibrate_handheld, DEFVAL(500));
ClassDB::bind_method(D_METHOD("get_gravity"), &Input::get_gravity);
ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer);
ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer);

View file

@ -100,6 +100,7 @@ public:
virtual uint64_t get_joy_vibration_timestamp(int p_device) = 0;
virtual void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0) = 0;
virtual void stop_joy_vibration(int p_device) = 0;
virtual void vibrate_handheld(int p_duration_ms = 500) = 0;
virtual Point2 get_mouse_position() const = 0;
virtual Point2 get_last_mouse_speed() const = 0;

View file

@ -450,7 +450,7 @@ bool InputEventMouseButton::is_doubleclick() const {
Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
Vector2 g = p_xform.xform(get_global_position());
Vector2 g = get_global_position();
Vector2 l = p_xform.xform(get_position() + p_local_ofs);
Ref<InputEventMouseButton> mb;
@ -577,7 +577,7 @@ Vector2 InputEventMouseMotion::get_speed() const {
Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
Vector2 g = p_xform.xform(get_global_position());
Vector2 g = get_global_position();
Vector2 l = p_xform.xform(get_position() + p_local_ofs);
Vector2 r = p_xform.basis_xform(get_relative());
Vector2 s = p_xform.basis_xform(get_speed());

View file

@ -37,10 +37,6 @@
#include "core/typedefs.h"
#include "core/ustring.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
/**
* Input Event classes. These are used in the main loop.
* The events are pretty obvious.

View file

@ -33,10 +33,6 @@
#include "core/ustring.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
/*
Special Key:

View file

@ -49,6 +49,8 @@ void MainLoop::_bind_methods() {
BIND_VMETHOD(MethodInfo("_drop_files", PropertyInfo(Variant::POOL_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "from_screen")));
BIND_VMETHOD(MethodInfo("_finalize"));
BIND_VMETHOD(MethodInfo("_global_menu_action", PropertyInfo(Variant::NIL, "id"), PropertyInfo(Variant::NIL, "meta")));
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER);
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN);
@ -115,6 +117,12 @@ void MainLoop::drop_files(const Vector<String> &p_files, int p_from_screen) {
get_script_instance()->call("_drop_files", p_files, p_from_screen);
}
void MainLoop::global_menu_action(const Variant &p_id, const Variant &p_meta) {
if (get_script_instance())
get_script_instance()->call("_global_menu_action", p_id, p_meta);
}
void MainLoop::finish() {
if (get_script_instance()) {

View file

@ -35,10 +35,6 @@
#include "core/reference.h"
#include "core/script_language.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class MainLoop : public Object {
GDCLASS(MainLoop, Object);
@ -75,6 +71,7 @@ public:
virtual void finish();
virtual void drop_files(const Vector<String> &p_files, int p_from_screen = 0);
virtual void global_menu_action(const Variant &p_id, const Variant &p_meta);
void set_init_script(const Ref<Script> &p_init_script);

View file

@ -35,10 +35,6 @@
#include <stddef.h>
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
#ifndef PAD_ALIGN
#define PAD_ALIGN 16 //must always be greater than this at much
#endif

View file

@ -186,6 +186,11 @@ int OS::get_process_id() const {
return -1;
};
void OS::vibrate_handheld(int p_duration_ms) {
WARN_PRINTS("vibrate_handheld() only works with Android and iOS");
}
bool OS::is_stdout_verbose() const {
return _verbose_stdout;
@ -268,8 +273,7 @@ void OS::print_all_resources(String p_to_file) {
_OSPRF = FileAccess::open(p_to_file, FileAccess::WRITE, &err);
if (err != OK) {
_OSPRF = NULL;
ERR_EXPLAIN("Can't print all resources to file: " + String(p_to_file));
ERR_FAIL();
ERR_FAIL_MSG("Can't print all resources to file: " + String(p_to_file) + ".");
}
}
@ -487,10 +491,7 @@ void OS::_ensure_user_data_dir() {
da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
Error err = da->make_dir_recursive(dd);
if (err != OK) {
ERR_EXPLAIN("Error attempting to create data dir: " + dd);
}
ERR_FAIL_COND(err != OK);
ERR_FAIL_COND_MSG(err != OK, "Error attempting to create data dir: " + dd + ".");
memdelete(da);
}

View file

@ -41,10 +41,6 @@
#include <stdarg.h>
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class Mutex;
class OS {
@ -147,6 +143,11 @@ public:
static OS *get_singleton();
virtual void global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta){};
virtual void global_menu_add_separator(const String &p_menu){};
virtual void global_menu_remove_item(const String &p_menu, int p_idx){};
virtual void global_menu_clear(const String &p_menu){};
void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type = Logger::ERR_ERROR);
void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
@ -269,6 +270,7 @@ public:
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL) = 0;
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
virtual void vibrate_handheld(int p_duration_ms = 500);
virtual Error shell_open(String p_uri);
virtual Error set_cwd(const String &p_cwd);

View file

@ -33,10 +33,6 @@
#include "core/error_list.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class Semaphore {
protected:
static Semaphore *(*create_func)();

Some files were not shown because too many files have changed in this diff Show more