summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/linux_builds.yml6
-rw-r--r--editor/icons/RectangleShape2D.svg2
-rw-r--r--editor/property_editor.cpp15
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp77
-rw-r--r--modules/gdscript/gdscript_analyzer.h3
-rw-r--r--modules/gdscript/gdscript_compiler.h14
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp76
-rw-r--r--platform/iphone/in_app_store.h14
-rw-r--r--platform/iphone/in_app_store.mm284
-rw-r--r--platform/osx/display_server_osx.mm14
-rw-r--r--scene/gui/menu_button.cpp8
-rw-r--r--servers/rendering/rasterizer_rd/shader_compiler_rd.cpp2
-rw-r--r--servers/rendering/rasterizer_rd/shaders/tonemap.glsl2
13 files changed, 360 insertions, 157 deletions
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index b170889cb3..3dd1b755b8 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -138,12 +138,6 @@ jobs:
run: |
./bin/godot.linuxbsd.tools.64s --test
- - uses: actions/upload-artifact@v2
- with:
- name: ${{ github.job }}
- path: bin/*
- retention-days: 14
-
linux-template-mono:
runs-on: "ubuntu-20.04"
name: Template w/ Mono (target=release, tools=no)
diff --git a/editor/icons/RectangleShape2D.svg b/editor/icons/RectangleShape2D.svg
index f0d6c54dc9..415940e68f 100644
--- a/editor/icons/RectangleShape2D.svg
+++ b/editor/icons/RectangleShape2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><rect fill="none" height="8" rx=".000017" stroke="#68b6ff" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2" width="12" x="2" y="4"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><rect fill="none" height="8" rx=".000017" stroke="#e0e0e0" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2" width="12" x="2" y="4"/></svg>
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index cb56358ae6..7f1b5347cf 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -1697,13 +1697,18 @@ void CustomPropertyEditor::config_value_editors(int p_amount, int p_columns, int
int cell_width = 95;
int cell_height = 25;
int cell_margin = 5;
- int hor_spacing = 5; // Spacing between labels and their values
-
int rows = ((p_amount - 1) / p_columns) + 1;
set_size(Size2(cell_margin + p_label_w + (cell_width + cell_margin + p_label_w) * p_columns, cell_margin + (cell_height + cell_margin) * rows) * EDSCALE);
for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
+ value_label[i]->get_parent()->remove_child(value_label[i]);
+ value_editor[i]->get_parent()->remove_child(value_editor[i]);
+
+ int box_id = i / p_columns;
+ value_hboxes[box_id]->add_child(value_label[i]);
+ value_hboxes[box_id]->add_child(value_editor[i]);
+
if (i < MAX_VALUE_EDITORS / 4) {
if (i <= p_amount / 4) {
value_hboxes[i]->show();
@@ -1712,16 +1717,10 @@ void CustomPropertyEditor::config_value_editors(int p_amount, int p_columns, int
}
}
- int c = i % p_columns;
- int r = i / p_columns;
-
if (i < p_amount) {
value_editor[i]->show();
value_label[i]->show();
value_label[i]->set_text(i < p_strings.size() ? p_strings[i] : String(""));
- value_editor[i]->set_position(Point2(cell_margin + p_label_w + hor_spacing + (cell_width + cell_margin + p_label_w + hor_spacing) * c, cell_margin + (cell_height + cell_margin) * r) * EDSCALE);
- value_editor[i]->set_size(Size2(cell_width, cell_height));
- value_label[i]->set_position(Point2(cell_margin + (cell_width + cell_margin + p_label_w + hor_spacing) * c, cell_margin + (cell_height + cell_margin) * r) * EDSCALE);
value_editor[i]->set_editable(!read_only);
} else {
value_editor[i]->hide();
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 943a49060f..5250115608 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -577,6 +577,12 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
GDScriptParser::DataType datatype = member.constant->get_datatype();
if (member.constant->initializer) {
+ if (member.constant->initializer->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer));
+ } else if (member.constant->initializer->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(member.constant->initializer));
+ }
+
if (!member.constant->initializer->is_constant) {
push_error(R"(Initializer for a constant must be a constant expression.)", member.constant->initializer);
}
@@ -1113,6 +1119,11 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
GDScriptParser::DataType type;
reduce_expression(p_constant->initializer);
+ if (p_constant->initializer->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer));
+ } else if (p_constant->initializer->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_constant->initializer));
+ }
if (!p_constant->initializer->is_constant) {
push_error(vformat(R"(Assigned value for constant "%s" isn't a constant expression.)", p_constant->identifier->name), p_constant->initializer);
@@ -1422,22 +1433,9 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre
}
void GDScriptAnalyzer::reduce_array(GDScriptParser::ArrayNode *p_array) {
- bool all_is_constant = true;
-
for (int i = 0; i < p_array->elements.size(); i++) {
GDScriptParser::ExpressionNode *element = p_array->elements[i];
reduce_expression(element);
- all_is_constant = all_is_constant && element->is_constant;
- }
-
- if (all_is_constant) {
- Array array;
- array.resize(p_array->elements.size());
- for (int i = 0; i < p_array->elements.size(); i++) {
- array[i] = p_array->elements[i]->reduced_value;
- }
- p_array->is_constant = true;
- p_array->reduced_value = array;
}
// It's array in any case.
@@ -1984,8 +1982,6 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) {
}
void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary) {
- bool all_is_constant = true;
-
HashMap<Variant, GDScriptParser::ExpressionNode *, VariantHasher, VariantComparator> elements;
for (int i = 0; i < p_dictionary->elements.size(); i++) {
@@ -1994,7 +1990,6 @@ void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dicti
reduce_expression(element.key);
}
reduce_expression(element.value);
- all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant;
if (element.key->is_constant) {
if (elements.has(element.key->reduced_value)) {
@@ -2005,16 +2000,6 @@ void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dicti
}
}
- if (all_is_constant) {
- Dictionary dict;
- for (int i = 0; i < p_dictionary->elements.size(); i++) {
- const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
- dict[element.key->reduced_value] = element.value->reduced_value;
- }
- p_dictionary->is_constant = true;
- p_dictionary->reduced_value = dict;
- }
-
// It's dictionary in any case.
GDScriptParser::DataType dict_type;
dict_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
@@ -2737,6 +2722,46 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
p_unary_op->set_datatype(result);
}
+void GDScriptAnalyzer::const_fold_array(GDScriptParser::ArrayNode *p_array) {
+ bool all_is_constant = true;
+
+ for (int i = 0; i < p_array->elements.size(); i++) {
+ GDScriptParser::ExpressionNode *element = p_array->elements[i];
+ all_is_constant = all_is_constant && element->is_constant;
+ if (!all_is_constant) {
+ return;
+ }
+ }
+
+ Array array;
+ array.resize(p_array->elements.size());
+ for (int i = 0; i < p_array->elements.size(); i++) {
+ array[i] = p_array->elements[i]->reduced_value;
+ }
+ p_array->is_constant = true;
+ p_array->reduced_value = array;
+}
+
+void GDScriptAnalyzer::const_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary) {
+ bool all_is_constant = true;
+
+ for (int i = 0; i < p_dictionary->elements.size(); i++) {
+ const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
+ all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant;
+ if (!all_is_constant) {
+ return;
+ }
+ }
+
+ Dictionary dict;
+ for (int i = 0; i < p_dictionary->elements.size(); i++) {
+ const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
+ dict[element.key->reduced_value] = element.value->reduced_value;
+ }
+ p_dictionary->is_constant = true;
+ p_dictionary->reduced_value = dict;
+}
+
GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType result;
result.is_constant = true;
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index c3911cce76..f3cbb320b7 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -89,6 +89,9 @@ class GDScriptAnalyzer {
void reduce_ternary_op(GDScriptParser::TernaryOpNode *p_ternary_op);
void reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op);
+ void const_fold_array(GDScriptParser::ArrayNode *p_array);
+ void const_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary);
+
// Helpers.
GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);
GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const;
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index db02079d26..fe34d6cba3 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -51,12 +51,11 @@ class GDScriptCompiler {
GDScriptCodeGenerator *generator = nullptr;
Map<StringName, GDScriptCodeGenerator::Address> parameters;
Map<StringName, GDScriptCodeGenerator::Address> locals;
- List<Set<StringName>> locals_in_scope;
+ List<Map<StringName, GDScriptCodeGenerator::Address>> locals_stack;
GDScriptCodeGenerator::Address add_local(const StringName &p_name, const GDScriptDataType &p_type) {
uint32_t addr = generator->add_local(p_name, p_type);
locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_VARIABLE, addr, p_type);
- locals_in_scope.back()->get().insert(p_name);
return locals[p_name];
}
@@ -102,17 +101,14 @@ class GDScriptCompiler {
}
void start_block() {
- Set<StringName> scope;
- locals_in_scope.push_back(scope);
+ Map<StringName, GDScriptCodeGenerator::Address> old_locals = locals;
+ locals_stack.push_back(old_locals);
generator->start_block();
}
void end_block() {
- Set<StringName> &scope = locals_in_scope.back()->get();
- for (Set<StringName>::Element *E = scope.front(); E; E = E->next()) {
- locals.erase(E->get());
- }
- locals_in_scope.pop_back();
+ locals = locals_stack.back()->get();
+ locals_stack.pop_back();
generator->end_block();
}
};
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index 68d9984b43..931b683a44 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -30,10 +30,13 @@
#include "test_gdscript.h"
+#include "core/io/file_access_pack.h"
#include "core/os/file_access.h"
#include "core/os/main_loop.h"
#include "core/os/os.h"
+#include "core/project_settings.h"
#include "core/string_builder.h"
+#include "scene/resources/packed_scene.h"
#include "modules/gdscript/gdscript_analyzer.h"
#include "modules/gdscript/gdscript_compiler.h"
@@ -179,6 +182,60 @@ static void test_compiler(const String &p_code, const String &p_script_path, con
}
}
+void init_autoloads() {
+ Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+
+ // First pass, add the constants so they exist before any script is loaded.
+ for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
+ const ProjectSettings::AutoloadInfo &info = E->get();
+
+ if (info.is_singleton) {
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(info.name, Variant());
+ }
+ }
+ }
+
+ // Second pass, load into global constants.
+ for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
+ const ProjectSettings::AutoloadInfo &info = E->get();
+
+ if (!info.is_singleton) {
+ // Skip non-singletons since we don't have a scene tree here anyway.
+ continue;
+ }
+
+ RES res = ResourceLoader::load(info.path);
+ ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path);
+ Node *n = nullptr;
+ if (res->is_class("PackedScene")) {
+ Ref<PackedScene> ps = res;
+ n = ps->instance();
+ } else if (res->is_class("Script")) {
+ Ref<Script> script_res = res;
+ StringName ibt = script_res->get_instance_base_type();
+ bool valid_type = ClassDB::is_parent_class(ibt, "Node");
+ ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path);
+
+ Object *obj = ClassDB::instance(ibt);
+
+ ERR_CONTINUE_MSG(obj == nullptr,
+ "Cannot instance script for autoload, expected 'Node' inheritance, got: " +
+ String(ibt));
+
+ n = Object::cast_to<Node>(obj);
+ n->set_script(script_res);
+ }
+
+ ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path);
+ n->set_name(info.name);
+
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(info.name, n);
+ }
+ }
+}
+
void test(TestType p_type) {
List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
@@ -195,6 +252,21 @@ void test(TestType p_type) {
FileAccessRef fa = FileAccess::open(test, FileAccess::READ);
ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test);
+ // Init PackedData since it's used by ProjectSettings.
+ PackedData *packed_data = memnew(PackedData);
+
+ // Setup project settings since it's needed by the languages to get the global scripts.
+ // This also sets up the base resource path.
+ Error err = ProjectSettings::get_singleton()->setup(fa->get_path_absolute().get_base_dir(), String(), true);
+ if (err) {
+ print_line("Could not load project settings.");
+ // Keep going since some scripts still work without this.
+ }
+
+ // Initialize the language for the test routine.
+ ScriptServer::init_languages();
+ init_autoloads();
+
Vector<uint8_t> buf;
int flen = fa->get_len();
buf.resize(fa->get_len() + 1);
@@ -226,6 +298,10 @@ void test(TestType p_type) {
case TEST_BYTECODE:
print_line("Not implemented.");
}
+
+ // Destroy stuff we set up earlier.
+ ScriptServer::finish_languages();
+ memdelete(packed_data);
}
} // namespace TestGDScript
diff --git a/platform/iphone/in_app_store.h b/platform/iphone/in_app_store.h
index ccf31876a9..1b8f84ec7b 100644
--- a/platform/iphone/in_app_store.h
+++ b/platform/iphone/in_app_store.h
@@ -35,6 +35,17 @@
#include "core/class_db.h"
+#ifdef __OBJC__
+@class GodotProductsDelegate;
+@class GodotTransactionsObserver;
+
+typedef GodotProductsDelegate InAppStoreProductDelegate;
+typedef GodotTransactionsObserver InAppStoreTransactionObserver;
+#else
+typedef void InAppStoreProductDelegate;
+typedef void InAppStoreTransactionObserver;
+#endif
+
class InAppStore : public Object {
GDCLASS(InAppStore, Object);
@@ -43,6 +54,9 @@ class InAppStore : public Object {
List<Variant> pending_events;
+ InAppStoreProductDelegate *products_request_delegate;
+ InAppStoreTransactionObserver *transactions_observer;
+
public:
Error request_product_info(Dictionary p_params);
Error restore_purchases();
diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm
index 2b973dfbcf..3eec9dae69 100644
--- a/platform/iphone/in_app_store.mm
+++ b/platform/iphone/in_app_store.mm
@@ -32,24 +32,22 @@
#include "in_app_store.h"
-extern "C" {
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
-};
-bool auto_finish_transactions = true;
-NSMutableDictionary *pending_transactions = [NSMutableDictionary dictionary];
-static NSArray *latestProducts;
+InAppStore *InAppStore::instance = NULL;
@interface SKProduct (LocalizedPrice)
@property(nonatomic, readonly) NSString *localizedPrice;
+
@end
//----------------------------------//
// SKProduct extension
//----------------------------------//
@implementation SKProduct (LocalizedPrice)
+
- (NSString *)localizedPrice {
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
@@ -61,29 +59,91 @@ static NSArray *latestProducts;
@end
-InAppStore *InAppStore::instance = NULL;
-
-void InAppStore::_bind_methods() {
- ClassDB::bind_method(D_METHOD("request_product_info"), &InAppStore::request_product_info);
- ClassDB::bind_method(D_METHOD("restore_purchases"), &InAppStore::restore_purchases);
- ClassDB::bind_method(D_METHOD("purchase"), &InAppStore::purchase);
+@interface GodotProductsDelegate : NSObject <SKProductsRequestDelegate>
- ClassDB::bind_method(D_METHOD("get_pending_event_count"), &InAppStore::get_pending_event_count);
- ClassDB::bind_method(D_METHOD("pop_pending_event"), &InAppStore::pop_pending_event);
- ClassDB::bind_method(D_METHOD("finish_transaction"), &InAppStore::finish_transaction);
- ClassDB::bind_method(D_METHOD("set_auto_finish_transaction"), &InAppStore::set_auto_finish_transaction);
-};
+@property(nonatomic, strong) NSMutableArray *loadedProducts;
+@property(nonatomic, strong) NSMutableArray *pendingRequests;
-@interface ProductsDelegate : NSObject <SKProductsRequestDelegate> {
-};
+- (void)performRequestWithProductIDs:(NSSet *)productIDs;
+- (Error)purchaseProductWithProductID:(NSString *)productID;
+- (void)reset;
@end
-@implementation ProductsDelegate
+@implementation GodotProductsDelegate
+
+- (instancetype)init {
+ self = [super init];
+
+ if (self) {
+ [self godot_commonInit];
+ }
+
+ return self;
+}
+
+- (void)godot_commonInit {
+ self.loadedProducts = [NSMutableArray new];
+ self.pendingRequests = [NSMutableArray new];
+}
+
+- (void)performRequestWithProductIDs:(NSSet *)productIDs {
+ SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:productIDs];
+
+ request.delegate = self;
+ [self.pendingRequests addObject:request];
+ [request start];
+}
+
+- (Error)purchaseProductWithProductID:(NSString *)productID {
+ SKProduct *product = nil;
+
+ NSLog(@"searching for product!");
+
+ if (self.loadedProducts) {
+ for (SKProduct *storedProduct in self.loadedProducts) {
+ if ([storedProduct.productIdentifier isEqualToString:productID]) {
+ product = storedProduct;
+ break;
+ }
+ }
+ }
+
+ if (!product) {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NSLog(@"product found!");
+
+ SKPayment *payment = [SKPayment paymentWithProduct:product];
+ [[SKPaymentQueue defaultQueue] addPayment:payment];
+
+ NSLog(@"purchase sent!");
+
+ return OK;
+}
+
+- (void)reset {
+ [self.loadedProducts removeAllObjects];
+ [self.pendingRequests removeAllObjects];
+}
+
+- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
+ [self.pendingRequests removeObject:request];
+
+ Dictionary ret;
+ ret["type"] = "product_info";
+ ret["result"] = "error";
+ ret["error"] = String::utf8([error.localizedDescription UTF8String]);
+
+ InAppStore::get_singleton()->_post_event(ret);
+}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
+ [self.pendingRequests removeObject:request];
+
NSArray *products = response.products;
- latestProducts = products;
+ [self.loadedProducts addObjectsFromArray:products];
Dictionary ret;
ret["type"] = "product_info";
@@ -107,7 +167,8 @@ void InAppStore::_bind_methods() {
ids.push_back(String::utf8([product.productIdentifier UTF8String]));
localized_prices.push_back(String::utf8([product.localizedPrice UTF8String]));
currency_codes.push_back(String::utf8([[[product priceLocale] objectForKey:NSLocaleCurrencyCode] UTF8String]));
- };
+ }
+
ret["titles"] = titles;
ret["descriptions"] = descriptions;
ret["prices"] = prices;
@@ -119,50 +180,54 @@ void InAppStore::_bind_methods() {
for (NSString *ipid in response.invalidProductIdentifiers) {
invalid_ids.push_back(String::utf8([ipid UTF8String]));
- };
+ }
+
ret["invalid_ids"] = invalid_ids;
InAppStore::get_singleton()->_post_event(ret);
-};
+}
@end
-Error InAppStore::request_product_info(Dictionary p_params) {
- ERR_FAIL_COND_V(!p_params.has("product_ids"), ERR_INVALID_PARAMETER);
+@interface GodotTransactionsObserver : NSObject <SKPaymentTransactionObserver>
- PackedStringArray pids = p_params["product_ids"];
- printf("************ request product info! %i\n", pids.size());
+@property(nonatomic, assign) BOOL shouldAutoFinishTransactions;
+@property(nonatomic, strong) NSMutableDictionary *pendingTransactions;
- NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:pids.size()];
- for (int i = 0; i < pids.size(); i++) {
- printf("******** adding %s to product list\n", pids[i].utf8().get_data());
- NSString *pid = [[NSString alloc] initWithUTF8String:pids[i].utf8().get_data()];
- [array addObject:pid];
- };
+- (void)finishTransactionWithProductID:(NSString *)productID;
+- (void)reset;
- NSSet *products = [[NSSet alloc] initWithArray:array];
- SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:products];
+@end
- ProductsDelegate *delegate = [[ProductsDelegate alloc] init];
+@implementation GodotTransactionsObserver
- request.delegate = delegate;
- [request start];
+- (instancetype)init {
+ self = [super init];
- return OK;
-};
+ if (self) {
+ [self godot_commonInit];
+ }
-Error InAppStore::restore_purchases() {
- printf("restoring purchases!\n");
- [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
+ return self;
+}
- return OK;
-};
+- (void)godot_commonInit {
+ self.pendingTransactions = [NSMutableDictionary new];
+}
-@interface TransObserver : NSObject <SKPaymentTransactionObserver> {
-};
-@end
+- (void)finishTransactionWithProductID:(NSString *)productID {
+ SKPaymentTransaction *transaction = self.pendingTransactions[productID];
+
+ if (transaction) {
+ [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
+ }
-@implementation TransObserver
+ self.pendingTransactions[productID] = nil;
+}
+
+- (void)reset {
+ [self.pendingTransactions removeAllObjects];
+}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
printf("transactions updated!\n");
@@ -190,6 +255,7 @@ Error InAppStore::restore_purchases() {
receipt = [NSData dataWithContentsOfURL:receiptFileURL];
NSString *receipt_to_send = nil;
+
if (receipt != nil) {
receipt_to_send = [receipt base64EncodedStringWithOptions:0];
}
@@ -200,13 +266,13 @@ Error InAppStore::restore_purchases() {
InAppStore::get_singleton()->_post_event(ret);
- if (auto_finish_transactions) {
+ if (self.shouldAutoFinishTransactions) {
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
} else {
- [pending_transactions setObject:transaction forKey:transaction.payment.productIdentifier];
+ self.pendingTransactions[transaction.payment.productIdentifier] = transaction;
}
- }; break;
+ } break;
case SKPaymentTransactionStateFailed: {
printf("status transaction failed!\n");
String pid = String::utf8([transaction.payment.productIdentifier UTF8String]);
@@ -231,95 +297,119 @@ Error InAppStore::restore_purchases() {
} break;
default: {
printf("status default %i!\n", (int)transaction.transactionState);
- }; break;
- };
- };
-};
+ } break;
+ }
+ }
+}
@end
-Error InAppStore::purchase(Dictionary p_params) {
- ERR_FAIL_COND_V(![SKPaymentQueue canMakePayments], ERR_UNAVAILABLE);
- if (![SKPaymentQueue canMakePayments])
- return ERR_UNAVAILABLE;
+void InAppStore::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("request_product_info"), &InAppStore::request_product_info);
+ ClassDB::bind_method(D_METHOD("restore_purchases"), &InAppStore::restore_purchases);
+ ClassDB::bind_method(D_METHOD("purchase"), &InAppStore::purchase);
- printf("purchasing!\n");
- ERR_FAIL_COND_V(!p_params.has("product_id"), ERR_INVALID_PARAMETER);
+ ClassDB::bind_method(D_METHOD("get_pending_event_count"), &InAppStore::get_pending_event_count);
+ ClassDB::bind_method(D_METHOD("pop_pending_event"), &InAppStore::pop_pending_event);
+ ClassDB::bind_method(D_METHOD("finish_transaction"), &InAppStore::finish_transaction);
+ ClassDB::bind_method(D_METHOD("set_auto_finish_transaction"), &InAppStore::set_auto_finish_transaction);
+}
- NSString *pid = [[NSString alloc] initWithUTF8String:String(p_params["product_id"]).utf8().get_data()];
+Error InAppStore::request_product_info(Dictionary p_params) {
+ ERR_FAIL_COND_V(!p_params.has("product_ids"), ERR_INVALID_PARAMETER);
- SKProduct *product = nil;
+ PackedStringArray pids = p_params["product_ids"];
+ printf("************ request product info! %i\n", pids.size());
- if (latestProducts) {
- for (SKProduct *storedProduct in latestProducts) {
- if ([storedProduct.productIdentifier isEqualToString:pid]) {
- product = storedProduct;
- break;
- }
- }
- }
+ NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:pids.size()];
+ for (int i = 0; i < pids.size(); i++) {
+ printf("******** adding %s to product list\n", pids[i].utf8().get_data());
+ NSString *pid = [[NSString alloc] initWithUTF8String:pids[i].utf8().get_data()];
+ [array addObject:pid];
+ };
- if (!product) {
- return ERR_INVALID_PARAMETER;
- }
+ NSSet *products = [[NSSet alloc] initWithArray:array];
- SKPayment *payment = [SKPayment paymentWithProduct:product];
- SKPaymentQueue *defq = [SKPaymentQueue defaultQueue];
- [defq addPayment:payment];
- printf("purchase sent!\n");
+ [products_request_delegate performRequestWithProductIDs:products];
return OK;
-};
+}
+
+Error InAppStore::restore_purchases() {
+ printf("restoring purchases!\n");
+ [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
+
+ return OK;
+}
+
+Error InAppStore::purchase(Dictionary p_params) {
+ ERR_FAIL_COND_V(![SKPaymentQueue canMakePayments], ERR_UNAVAILABLE);
+ if (![SKPaymentQueue canMakePayments]) {
+ return ERR_UNAVAILABLE;
+ }
+
+ printf("purchasing!\n");
+ Dictionary params = p_params;
+ ERR_FAIL_COND_V(!params.has("product_id"), ERR_INVALID_PARAMETER);
+
+ NSString *pid = [[NSString alloc] initWithUTF8String:String(params["product_id"]).utf8().get_data()];
+
+ return [products_request_delegate purchaseProductWithProductID:pid];
+}
int InAppStore::get_pending_event_count() {
return pending_events.size();
-};
+}
Variant InAppStore::pop_pending_event() {
Variant front = pending_events.front()->get();
pending_events.pop_front();
return front;
-};
+}
void InAppStore::_post_event(Variant p_event) {
pending_events.push_back(p_event);
-};
+}
void InAppStore::_record_purchase(String product_id) {
String skey = "purchased/" + product_id;
NSString *key = [[NSString alloc] initWithUTF8String:skey.utf8().get_data()];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:key];
[[NSUserDefaults standardUserDefaults] synchronize];
-};
+}
InAppStore *InAppStore::get_singleton() {
return instance;
-};
+}
InAppStore::InAppStore() {
ERR_FAIL_COND(instance != NULL);
instance = this;
- auto_finish_transactions = false;
- TransObserver *observer = [[TransObserver alloc] init];
- [[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
- //pending_transactions = [NSMutableDictionary dictionary];
-};
+ products_request_delegate = [[GodotProductsDelegate alloc] init];
+ transactions_observer = [[GodotTransactionsObserver alloc] init];
+
+ [[SKPaymentQueue defaultQueue] addTransactionObserver:transactions_observer];
+}
void InAppStore::finish_transaction(String product_id) {
NSString *prod_id = [NSString stringWithCString:product_id.utf8().get_data() encoding:NSUTF8StringEncoding];
- if ([pending_transactions objectForKey:prod_id]) {
- [[SKPaymentQueue defaultQueue] finishTransaction:[pending_transactions objectForKey:prod_id]];
- [pending_transactions removeObjectForKey:prod_id];
- }
-};
+ [transactions_observer finishTransactionWithProductID:prod_id];
+}
void InAppStore::set_auto_finish_transaction(bool b) {
- auto_finish_transactions = b;
+ transactions_observer.shouldAutoFinishTransactions = b;
}
-InAppStore::~InAppStore() {}
+InAppStore::~InAppStore() {
+ [products_request_delegate reset];
+ [transactions_observer reset];
+
+ products_request_delegate = nil;
+ [[SKPaymentQueue defaultQueue] removeTransactionObserver:transactions_observer];
+ transactions_observer = nil;
+}
#endif
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index cd5b71890c..1ad7117b39 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -63,6 +63,8 @@
#define DS_OSX ((DisplayServerOSX *)(DisplayServerOSX::get_singleton()))
+static bool ignore_momentum_scroll = false;
+
static void _get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> r_state) {
r_state->set_shift((p_osx_state & NSEventModifierFlagShift));
r_state->set_control((p_osx_state & NSEventModifierFlagControl));
@@ -1304,6 +1306,8 @@ static int remapKey(unsigned int key, unsigned int state) {
ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+ ignore_momentum_scroll = true;
+
// Ignore all input if IME input is in progress
if (!imeInputEventInProgress) {
NSString *characters = [event characters];
@@ -1348,6 +1352,8 @@ static int remapKey(unsigned int key, unsigned int state) {
}
- (void)flagsChanged:(NSEvent *)event {
+ ignore_momentum_scroll = true;
+
// Ignore all input if IME input is in progress
if (!imeInputEventInProgress) {
DisplayServerOSX::KeyEvent ke;
@@ -1507,6 +1513,14 @@ inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy
deltaY *= 0.03;
}
+ if ([event momentumPhase] != NSEventPhaseNone) {
+ if (ignore_momentum_scroll) {
+ return;
+ }
+ } else {
+ ignore_momentum_scroll = false;
+ }
+
if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) {
sendPanEvent(window_id, deltaX, deltaY, [event modifierFlags]);
} else {
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 9b1738ec79..d65e98ea46 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -53,17 +53,9 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
}
void MenuButton::pressed() {
- {
- Window *w = Object::cast_to<Window>(get_viewport());
- if (w && !w->is_embedding_subwindows()) {
- print_line("windowpos: " + w->get_position());
- }
- }
Size2 size = get_size();
Point2 gp = get_screen_position();
-
- print_line("screenpos: " + gp);
gp.y += get_size().y;
popup->set_position(gp);
diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
index 9597d2cbb2..0a0c343e57 100644
--- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
@@ -1295,6 +1295,8 @@ void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
texture_functions.insert("textureLod");
texture_functions.insert("textureProjLod");
texture_functions.insert("textureGrad");
+ texture_functions.insert("textureSize");
+ texture_functions.insert("texelFetch");
}
ShaderCompilerRD::ShaderCompilerRD() {
diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl
index ee66de4192..341cdab1ef 100644
--- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl
@@ -305,8 +305,6 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
}
}
-#define QUARTER_COLOR 1.0 / 1024.0
-
// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).