feat: updated godot version
This commit is contained in:
parent
0c508b0831
commit
42b028dbb5
4694 changed files with 236470 additions and 401376 deletions
|
|
@ -52,6 +52,7 @@ for name, path in env.module_list.items():
|
|||
|
||||
# Generate header to be included in `tests/test_main.cpp` to run module-specific tests.
|
||||
if env["tests"]:
|
||||
env.Append(CPPDEFINES=["TESTS_ENABLED"])
|
||||
env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_builders.modules_tests_builder))
|
||||
|
||||
# libmodules.a with only register_module_types.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
#include "core/string/print_string.h"
|
||||
|
||||
#define BCDEC_IMPLEMENTATION
|
||||
#include <thirdparty/misc/bcdec.h>
|
||||
#include "thirdparty/misc/bcdec.h"
|
||||
|
||||
inline void bcdec_bc6h_half_s(const void *compressedBlock, void *decompressedBlock, int destinationPitch) {
|
||||
bcdec_bc6h_half(compressedBlock, decompressedBlock, destinationPitch, true);
|
||||
|
|
|
|||
|
|
@ -30,28 +30,16 @@
|
|||
|
||||
#include "image_compress_betsy.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
#include "betsy_bc1.h"
|
||||
|
||||
#include "alpha_stitch.glsl.gen.h"
|
||||
#include "bc1.glsl.gen.h"
|
||||
#include "bc4.glsl.gen.h"
|
||||
#include "bc6h.glsl.gen.h"
|
||||
#include "betsy_bc1.h"
|
||||
#include "rgb_to_rgba.glsl.gen.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "core/os/os.h"
|
||||
#include "servers/display/display_server.h"
|
||||
#include "servers/rendering/rendering_context_driver.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
#include "servers/rendering/rendering_device_binds.h"
|
||||
#include "servers/rendering/rendering_server.h"
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#include "drivers/vulkan/rendering_context_driver_vulkan.h"
|
||||
#endif
|
||||
#if defined(METAL_ENABLED)
|
||||
#include "drivers/metal/rendering_context_driver_metal.h"
|
||||
#endif
|
||||
|
||||
static Mutex betsy_mutex;
|
||||
static BetsyCompressor *betsy = nullptr;
|
||||
|
|
|
|||
|
|
@ -32,11 +32,18 @@
|
|||
|
||||
#include "core/io/image.h"
|
||||
#include "core/object/worker_thread_pool.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/command_queue_mt.h"
|
||||
|
||||
class RDShaderFile;
|
||||
class RenderingDevice;
|
||||
class RenderingContextDriver;
|
||||
#include "servers/rendering/rendering_device_binds.h"
|
||||
#include "servers/rendering/rendering_server_default.h"
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#include "drivers/vulkan/rendering_context_driver_vulkan.h"
|
||||
#endif
|
||||
#if defined(METAL_ENABLED)
|
||||
#include "drivers/metal/rendering_context_driver_metal.h"
|
||||
#endif
|
||||
|
||||
enum BetsyFormat {
|
||||
BETSY_FORMAT_BC1,
|
||||
|
|
|
|||
|
|
@ -6,25 +6,19 @@ Import("env_modules")
|
|||
|
||||
env_camera = env_modules.Clone()
|
||||
|
||||
if env["platform"] in ["windows", "macos", "linuxbsd", "android", "ios", "visionos"]:
|
||||
if env["platform"] in ["windows", "macos", "linuxbsd", "android"]:
|
||||
env_camera.add_source_files(env.modules_sources, "register_types.cpp")
|
||||
|
||||
if env["platform"] == "windows":
|
||||
env_camera.add_source_files(env.modules_sources, "camera_win.cpp")
|
||||
|
||||
elif env["platform"] == "macos":
|
||||
env_camera.add_source_files(env.modules_sources, "camera_apple.mm")
|
||||
env_camera.add_source_files(env.modules_sources, "camera_macos.mm")
|
||||
|
||||
elif env["platform"] == "android":
|
||||
env_camera.add_source_files(env.modules_sources, "camera_android.cpp")
|
||||
env.Append(LIBS=["camera2ndk", "mediandk"])
|
||||
|
||||
elif env["platform"] in ["ios", "visionos"]:
|
||||
ext_module_source = ["camera_apple.mm"]
|
||||
ext_camera_lib = env_camera.add_library("#bin/libgodot_camera", ext_module_source)
|
||||
env.Append(LIBS_EXTERNAL=[ext_camera_lib])
|
||||
env.Append(MODULES_EXTERNAL=["_camera"])
|
||||
|
||||
elif env["platform"] == "linuxbsd":
|
||||
env_camera.add_source_files(env.modules_sources, "camera_linux.cpp")
|
||||
env_camera.add_source_files(env.modules_sources, "camera_feed_linux.cpp")
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include "camera_android.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
|
||||
#include "platform/android/display_server_android.h"
|
||||
#include "platform/android/java_godot_io_wrapper.h"
|
||||
#include "platform/android/os_android.h"
|
||||
|
|
@ -73,7 +72,7 @@ public:
|
|||
|
||||
#ifndef IF_EQUAL_RETURN
|
||||
#define MAKE_FORMAT_CONST(suffix) AIMAGE_FORMAT_##suffix
|
||||
#define IF_EQUAL_RETURN(param, val) \
|
||||
#define IF_EQUAL_RETURN(param, val) \
|
||||
if (MAKE_FORMAT_CONST(val) == param) \
|
||||
return #val
|
||||
#endif
|
||||
|
|
@ -90,7 +89,8 @@ String GetFormatName(const int32_t &format) {
|
|||
// CameraFeedAndroid - Subclass for our camera feed on Android
|
||||
|
||||
CameraFeedAndroid::CameraFeedAndroid(ACameraManager *manager, ACameraMetadata *metadata, const char *id,
|
||||
CameraFeed::FeedPosition position, int32_t orientation) {
|
||||
CameraFeed::FeedPosition position, int32_t orientation) :
|
||||
CameraFeed() {
|
||||
this->manager = manager;
|
||||
this->metadata = metadata;
|
||||
this->orientation = orientation;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
#include <camera/NdkCameraManager.h>
|
||||
#include <camera/NdkCameraMetadataTags.h>
|
||||
#include <media/NdkImageReader.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
enum class CameraFacing {
|
||||
|
|
|
|||
|
|
@ -350,7 +350,8 @@ bool CameraFeedLinux::set_format(int p_index, const Dictionary &p_parameters) {
|
|||
return true;
|
||||
}
|
||||
|
||||
CameraFeedLinux::CameraFeedLinux(const String &p_device_name) {
|
||||
CameraFeedLinux::CameraFeedLinux(const String &p_device_name) :
|
||||
CameraFeed() {
|
||||
device_name = p_device_name;
|
||||
_query_device(device_name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
#include "core/os/mutex.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "servers/camera/camera_server.h"
|
||||
|
||||
class CameraLinux : public CameraServer {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* camera_apple.h */
|
||||
/* camera_macos.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
|
@ -35,11 +35,11 @@
|
|||
|
||||
#include "servers/camera/camera_server.h"
|
||||
|
||||
class CameraApple : public CameraServer {
|
||||
GDSOFTCLASS(CameraApple, CameraServer);
|
||||
class CameraMacOS : public CameraServer {
|
||||
GDSOFTCLASS(CameraMacOS, CameraServer);
|
||||
|
||||
public:
|
||||
CameraApple() = default;
|
||||
CameraMacOS() = default;
|
||||
|
||||
void update_feeds();
|
||||
void set_monitoring_feeds(bool p_monitoring_feeds) override;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* camera_apple.mm */
|
||||
/* camera_macos.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
|
@ -31,14 +31,11 @@
|
|||
///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!!
|
||||
// If you fix something here, make sure you fix it there as well!
|
||||
|
||||
#import "camera_apple.h"
|
||||
#import "camera_macos.h"
|
||||
|
||||
#include "servers/camera/camera_feed.h"
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#ifdef IOS_ENABLED
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MyCaptureSession - This is a little helper class so we can capture our frames
|
||||
|
|
@ -66,30 +63,23 @@
|
|||
width[1] = 0;
|
||||
height[1] = 0;
|
||||
|
||||
#ifdef IOS_ENABLED
|
||||
if ([p_device lockForConfiguration:&error]) {
|
||||
if ([p_device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
|
||||
[p_device setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
|
||||
}
|
||||
if ([p_device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
|
||||
[p_device setExposureMode:AVCaptureExposureModeContinuousAutoExposure];
|
||||
}
|
||||
if ([p_device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance]) {
|
||||
[p_device setWhiteBalanceMode:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance];
|
||||
}
|
||||
#ifdef APPLE_EMBEDDED_ENABLED
|
||||
[p_device lockForConfiguration:&error];
|
||||
|
||||
[p_device unlockForConfiguration];
|
||||
}
|
||||
#endif // IOS_ENABLED
|
||||
[p_device setFocusMode:AVCaptureFocusModeLocked];
|
||||
[p_device setExposureMode:AVCaptureExposureModeLocked];
|
||||
[p_device setWhiteBalanceMode:AVCaptureWhiteBalanceModeLocked];
|
||||
|
||||
[p_device unlockForConfiguration];
|
||||
#endif // APPLE_EMBEDDED_ENABLED
|
||||
|
||||
[self beginConfiguration];
|
||||
|
||||
#ifdef IOS_ENABLED
|
||||
#ifdef APPLE_EMBEDDED_ENABLED
|
||||
self.sessionPreset = AVCaptureSessionPreset1280x720;
|
||||
#endif // IOS_ENABLED
|
||||
|
||||
input = [[AVCaptureDeviceInput alloc] initWithDevice:p_device error:&error];
|
||||
#endif // APPLE_EMBEDDED_ENABLED
|
||||
|
||||
input = [AVCaptureDeviceInput deviceInputWithDevice:p_device error:&error];
|
||||
if (!input) {
|
||||
print_line("Couldn't get input device for camera");
|
||||
[self commitConfiguration];
|
||||
|
|
@ -229,28 +219,6 @@
|
|||
// set our texture...
|
||||
feed->set_ycbcr_images(img[0], img[1]);
|
||||
|
||||
#ifdef IOS_ENABLED
|
||||
UIInterfaceOrientation orientation = [UIApplication sharedApplication].delegate.window.windowScene.interfaceOrientation;
|
||||
|
||||
Transform2D display_transform;
|
||||
switch (orientation) {
|
||||
case UIInterfaceOrientationPortrait: {
|
||||
display_transform = Transform2D(0.0, -1.0, -1.0, 0.0, 1.0, 1.0);
|
||||
} break;
|
||||
case UIInterfaceOrientationLandscapeRight: {
|
||||
display_transform = Transform2D(1.0, 0.0, 0.0, -1.0, 0.0, 1.0);
|
||||
} break;
|
||||
case UIInterfaceOrientationLandscapeLeft: {
|
||||
display_transform = Transform2D(-1.0, 0.0, 0.0, 1.0, 1.0, 0.0);
|
||||
} break;
|
||||
default: {
|
||||
display_transform = Transform2D(0.0, 1.0, 1.0, 0.0, 0.0, 0.0);
|
||||
} break;
|
||||
}
|
||||
|
||||
feed->set_transform(display_transform);
|
||||
#endif // IOS_ENABLED
|
||||
|
||||
// and unlock
|
||||
CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
|
||||
}
|
||||
|
|
@ -258,10 +226,10 @@
|
|||
@end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CameraFeedApple - Subclass for camera feeds in macOS
|
||||
// CameraFeedMacOS - Subclass for camera feeds in macOS
|
||||
|
||||
class CameraFeedApple : public CameraFeed {
|
||||
GDSOFTCLASS(CameraFeedApple, CameraFeed);
|
||||
class CameraFeedMacOS : public CameraFeed {
|
||||
GDSOFTCLASS(CameraFeedMacOS, CameraFeed);
|
||||
|
||||
private:
|
||||
AVCaptureDevice *device;
|
||||
|
|
@ -270,8 +238,8 @@ private:
|
|||
public:
|
||||
AVCaptureDevice *get_device() const;
|
||||
|
||||
CameraFeedApple();
|
||||
~CameraFeedApple();
|
||||
CameraFeedMacOS();
|
||||
~CameraFeedMacOS();
|
||||
|
||||
void set_device(AVCaptureDevice *p_device);
|
||||
|
||||
|
|
@ -279,23 +247,22 @@ public:
|
|||
void deactivate_feed() override;
|
||||
};
|
||||
|
||||
AVCaptureDevice *CameraFeedApple::get_device() const {
|
||||
AVCaptureDevice *CameraFeedMacOS::get_device() const {
|
||||
return device;
|
||||
}
|
||||
|
||||
CameraFeedApple::CameraFeedApple() {
|
||||
CameraFeedMacOS::CameraFeedMacOS() {
|
||||
device = nullptr;
|
||||
capture_session = nullptr;
|
||||
transform = Transform2D(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); /* should re-orientate this based on device orientation */
|
||||
}
|
||||
|
||||
CameraFeedApple::~CameraFeedApple() {
|
||||
CameraFeedMacOS::~CameraFeedMacOS() {
|
||||
if (is_active()) {
|
||||
deactivate_feed();
|
||||
}
|
||||
}
|
||||
|
||||
void CameraFeedApple::set_device(AVCaptureDevice *p_device) {
|
||||
void CameraFeedMacOS::set_device(AVCaptureDevice *p_device) {
|
||||
device = p_device;
|
||||
|
||||
// get some info
|
||||
|
|
@ -309,14 +276,14 @@ void CameraFeedApple::set_device(AVCaptureDevice *p_device) {
|
|||
};
|
||||
}
|
||||
|
||||
bool CameraFeedApple::activate_feed() {
|
||||
bool CameraFeedMacOS::activate_feed() {
|
||||
if (capture_session) {
|
||||
// Already recording.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start camera capture, check permission.
|
||||
if (@available(macOS 10.14, iOS 14.0, visionOS 1.0, *)) {
|
||||
if (@available(macOS 10.14, *)) {
|
||||
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||||
if (status == AVAuthorizationStatusAuthorized) {
|
||||
capture_session = [[MyCaptureSession alloc] initForFeed:this andDevice:device];
|
||||
|
|
@ -344,7 +311,7 @@ bool CameraFeedApple::activate_feed() {
|
|||
}
|
||||
}
|
||||
|
||||
void CameraFeedApple::deactivate_feed() {
|
||||
void CameraFeedMacOS::deactivate_feed() {
|
||||
// end camera capture if we have one
|
||||
if (capture_session) {
|
||||
[capture_session cleanup];
|
||||
|
|
@ -357,7 +324,7 @@ void CameraFeedApple::deactivate_feed() {
|
|||
// when devices are connected/disconnected
|
||||
|
||||
@interface MyDeviceNotifications : NSObject {
|
||||
CameraApple *camera_server;
|
||||
CameraMacOS *camera_server;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -368,7 +335,7 @@ void CameraFeedApple::deactivate_feed() {
|
|||
camera_server->update_feeds();
|
||||
}
|
||||
|
||||
- (id)initForServer:(CameraApple *)p_server {
|
||||
- (id)initForServer:(CameraMacOS *)p_server {
|
||||
if (self = [super init]) {
|
||||
camera_server = p_server;
|
||||
|
||||
|
|
@ -389,31 +356,13 @@ void CameraFeedApple::deactivate_feed() {
|
|||
MyDeviceNotifications *device_notifications = nil;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CameraApple - Subclass for our camera server on macOS
|
||||
// CameraMacOS - Subclass for our camera server on macOS
|
||||
|
||||
void CameraApple::update_feeds() {
|
||||
void CameraMacOS::update_feeds() {
|
||||
NSArray<AVCaptureDevice *> *devices = nullptr;
|
||||
#ifdef APPLE_EMBEDDED_ENABLED
|
||||
{
|
||||
NSMutableArray *deviceTypes = [NSMutableArray array];
|
||||
if (@available(iOS 14.0, visionOS 2.1, *)) {
|
||||
[deviceTypes addObject:AVCaptureDeviceTypeBuiltInWideAngleCamera];
|
||||
}
|
||||
#ifdef IOS_ENABLED
|
||||
[deviceTypes addObject:AVCaptureDeviceTypeBuiltInTelephotoCamera];
|
||||
[deviceTypes addObject:AVCaptureDeviceTypeBuiltInDualCamera];
|
||||
[deviceTypes addObject:AVCaptureDeviceTypeBuiltInTrueDepthCamera];
|
||||
[deviceTypes addObject:AVCaptureDeviceTypeBuiltInUltraWideCamera];
|
||||
[deviceTypes addObject:AVCaptureDeviceTypeBuiltInDualWideCamera];
|
||||
[deviceTypes addObject:AVCaptureDeviceTypeBuiltInTripleCamera];
|
||||
#endif // IOS_ENABLED
|
||||
AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
|
||||
devices = session.devices;
|
||||
}
|
||||
#else // APPLE_EMBEDDED_ENABLED
|
||||
#if defined(__x86_64__)
|
||||
if (@available(macOS 10.15, *)) {
|
||||
#endif // __x86_64__
|
||||
#endif
|
||||
AVCaptureDeviceDiscoverySession *session;
|
||||
if (@available(macOS 14.0, *)) {
|
||||
session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:[NSArray arrayWithObjects:AVCaptureDeviceTypeExternal, AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeContinuityCamera, nil] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
|
||||
|
|
@ -425,12 +374,11 @@ void CameraApple::update_feeds() {
|
|||
} else {
|
||||
devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
||||
}
|
||||
#endif // __x86_64__
|
||||
#endif // APPLE_EMBEDDED_ENABLED
|
||||
#endif
|
||||
|
||||
// Deactivate feeds that are gone before removing them.
|
||||
for (int i = feeds.size() - 1; i >= 0; i--) {
|
||||
Ref<CameraFeedApple> feed = (Ref<CameraFeedApple>)feeds[i];
|
||||
Ref<CameraFeedMacOS> feed = (Ref<CameraFeedMacOS>)feeds[i];
|
||||
if (feed.is_null()) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -446,7 +394,7 @@ void CameraApple::update_feeds() {
|
|||
for (AVCaptureDevice *device in devices) {
|
||||
bool found = false;
|
||||
for (int i = 0; i < feeds.size() && !found; i++) {
|
||||
Ref<CameraFeedApple> feed = (Ref<CameraFeedApple>)feeds[i];
|
||||
Ref<CameraFeedMacOS> feed = (Ref<CameraFeedMacOS>)feeds[i];
|
||||
if (feed.is_null()) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -456,7 +404,7 @@ void CameraApple::update_feeds() {
|
|||
};
|
||||
|
||||
if (!found) {
|
||||
Ref<CameraFeedApple> newfeed;
|
||||
Ref<CameraFeedMacOS> newfeed;
|
||||
newfeed.instantiate();
|
||||
newfeed->set_device(device);
|
||||
|
||||
|
|
@ -466,7 +414,7 @@ void CameraApple::update_feeds() {
|
|||
emit_signal(SNAME(CameraServer::feeds_updated_signal_name));
|
||||
}
|
||||
|
||||
void CameraApple::set_monitoring_feeds(bool p_monitoring_feeds) {
|
||||
void CameraMacOS::set_monitoring_feeds(bool p_monitoring_feeds) {
|
||||
if (p_monitoring_feeds == monitoring_feeds) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -483,14 +431,3 @@ void CameraApple::set_monitoring_feeds(bool p_monitoring_feeds) {
|
|||
device_notifications = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef APPLE_EMBEDDED_ENABLED
|
||||
|
||||
void register_camera_external_module() {
|
||||
CameraServer::make_default<CameraApple>();
|
||||
}
|
||||
|
||||
void unregister_camera_external_module() {
|
||||
}
|
||||
|
||||
#endif // APPLE_EMBEDDED_ENABLED
|
||||
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include "camera_win.h"
|
||||
|
||||
#include "servers/camera/camera_feed.h"
|
||||
|
||||
///@TODO sorry guys, I got about 80% through implementing this using DirectShow only
|
||||
// to find out Microsoft deprecated half the API and its replacement is as confusing
|
||||
// as they could make it. Joey suggested looking into libuvc which offers a more direct
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "servers/camera/camera_feed.h"
|
||||
#include "servers/camera/camera_server.h"
|
||||
|
||||
class CameraWindows : public CameraServer {
|
||||
|
|
|
|||
|
|
@ -3,14 +3,7 @@ def can_build(env, platform):
|
|||
|
||||
if sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd"):
|
||||
return False
|
||||
return (
|
||||
platform == "macos"
|
||||
or platform == "windows"
|
||||
or platform == "linuxbsd"
|
||||
or platform == "android"
|
||||
or platform == "ios"
|
||||
or platform == "visionos"
|
||||
)
|
||||
return platform == "macos" or platform == "windows" or platform == "linuxbsd" or platform == "android"
|
||||
|
||||
|
||||
def configure(env):
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
#include "camera_win.h"
|
||||
#endif
|
||||
#if defined(MACOS_ENABLED)
|
||||
#include "camera_apple.h"
|
||||
#include "camera_macos.h"
|
||||
#endif
|
||||
#if defined(ANDROID_ENABLED)
|
||||
#include "camera_android.h"
|
||||
|
|
@ -55,7 +55,7 @@ void initialize_camera_module(ModuleInitializationLevel p_level) {
|
|||
CameraServer::make_default<CameraWindows>();
|
||||
#endif
|
||||
#if defined(MACOS_ENABLED)
|
||||
CameraServer::make_default<CameraApple>();
|
||||
CameraServer::make_default<CameraMacOS>();
|
||||
#endif
|
||||
#if defined(ANDROID_ENABLED)
|
||||
CameraServer::make_default<CameraAndroid>();
|
||||
|
|
|
|||
|
|
@ -30,27 +30,18 @@
|
|||
|
||||
#include "csg_shape.h"
|
||||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/math/geometry_2d.h"
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "scene/main/scene_tree.h"
|
||||
#include "scene/resources/3d/navigation_mesh_source_geometry_data_3d.h"
|
||||
#include "scene/resources/navigation_mesh.h"
|
||||
#include "servers/rendering/rendering_server.h"
|
||||
|
||||
#ifdef DEV_ENABLED
|
||||
#include "core/io/json.h"
|
||||
#endif // DEV_ENABLED
|
||||
|
||||
#include "core/math/geometry_2d.h"
|
||||
#include "scene/resources/3d/navigation_mesh_source_geometry_data_3d.h"
|
||||
#include "scene/resources/navigation_mesh.h"
|
||||
#ifndef NAVIGATION_3D_DISABLED
|
||||
#include "servers/navigation_3d/navigation_server_3d.h"
|
||||
#endif // NAVIGATION_3D_DISABLED
|
||||
|
||||
#include <manifold/manifold.h>
|
||||
|
||||
#include <cfloat> // FLT_EPSILON
|
||||
|
||||
#ifndef NAVIGATION_3D_DISABLED
|
||||
Callable CSGShape3D::_navmesh_source_geometry_parsing_callback;
|
||||
RID CSGShape3D::_navmesh_source_geometry_parser;
|
||||
|
|
@ -204,26 +195,6 @@ void CSGShape3D::set_collision_priority(real_t p_priority) {
|
|||
real_t CSGShape3D::get_collision_priority() const {
|
||||
return collision_priority;
|
||||
}
|
||||
|
||||
void CSGShape3D::set_autosmooth(bool p_smooth) {
|
||||
autosmooth = p_smooth;
|
||||
_make_dirty();
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
bool CSGShape3D::is_autosmooth() const {
|
||||
return autosmooth;
|
||||
}
|
||||
|
||||
void CSGShape3D::set_smoothing_angle(const float p_angle) {
|
||||
smoothing_angle = p_angle;
|
||||
_make_dirty();
|
||||
}
|
||||
|
||||
float CSGShape3D::get_smoothing_angle() const {
|
||||
return smoothing_angle;
|
||||
}
|
||||
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
bool CSGShape3D::is_root_shape() const {
|
||||
|
|
@ -605,14 +576,10 @@ void CSGShape3D::update_shape() {
|
|||
CSGBrush *n = _get_brush();
|
||||
ERR_FAIL_NULL_MSG(n, "Cannot get CSGBrush.");
|
||||
|
||||
AHashMap<Vector3, Vector3> vec_map;
|
||||
|
||||
Vector<int> face_count;
|
||||
face_count.resize(n->materials.size() + 1);
|
||||
|
||||
Vector<Vector3> smooth_faces;
|
||||
LocalVector<Vector3> smooth_vertex;
|
||||
smooth_faces.resize(n->faces.size());
|
||||
smooth_vertex.resize(n->faces.size() * 3);
|
||||
|
||||
for (int i = 0; i < face_count.size(); i++) {
|
||||
face_count.write[i] = 0;
|
||||
}
|
||||
|
|
@ -622,72 +589,23 @@ void CSGShape3D::update_shape() {
|
|||
ERR_CONTINUE(mat < -1 || mat >= face_count.size());
|
||||
int idx = mat == -1 ? face_count.size() - 1 : mat;
|
||||
|
||||
Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]);
|
||||
if (n->faces[i].smooth) {
|
||||
Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
Vector3 v = n->faces[i].vertices[j];
|
||||
Vector3 *vec = vec_map.getptr(v);
|
||||
if (vec) {
|
||||
*vec += p.normal;
|
||||
} else {
|
||||
vec_map.insert(v, p.normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
smooth_faces.write[i] = p.normal;
|
||||
// Not sure if resize populates the LocalVector.
|
||||
smooth_vertex[i * 3 + 0] = Vector3(p.normal);
|
||||
smooth_vertex[i * 3 + 1] = Vector3(p.normal);
|
||||
smooth_vertex[i * 3 + 2] = Vector3(p.normal);
|
||||
// We could use a AHashMap Vector3, int to store the number of connections of each vertex position and end the loop earlier. But I'm not sure if the performance gains outweigh the cost.
|
||||
face_count.write[idx]++;
|
||||
}
|
||||
|
||||
if (autosmooth) {
|
||||
// We could add a `use_groups` property later to only apply autosmooth on smooth faces or respect smoothing groups in some way.
|
||||
if (smoothing_angle > 0.1) {
|
||||
float smooth_angle_rad = Math::cos(Math::deg_to_rad(smoothing_angle));
|
||||
for (int i = 0; i < smooth_faces.size(); i++) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int curr_vert = i * 3 + k;
|
||||
Vector3 vert_a = n->faces[i].vertices[k];
|
||||
for (int j = i + 1; j < smooth_faces.size(); j++) {
|
||||
// Compare the angles of faces instead of vertices.
|
||||
if (smooth_faces[i].dot(smooth_faces[j]) > smooth_angle_rad) {
|
||||
for (int h = 0; h < 3; h++) {
|
||||
Vector3 vert_b = n->faces[j].vertices[h];
|
||||
if (vert_a == vert_b) {
|
||||
int curr_j = j * 3 + h;
|
||||
smooth_vertex[curr_vert] += smooth_faces[j];
|
||||
smooth_vertex[curr_j] += smooth_faces[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
smooth_vertex[curr_vert].normalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < smooth_faces.size(); i++) {
|
||||
bool face_is_smooth = n->faces[i].smooth;
|
||||
if (face_is_smooth) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
Vector3 vert_a = n->faces[i].vertices[k];
|
||||
int curr_vert = i * 3 + k;
|
||||
// Skip the other vertices of the face as they will never occupy the same position.
|
||||
for (int j = i + 1; j < smooth_faces.size(); j++) {
|
||||
// Preparing for when and if we replace Vector of bool for Vector of int smoothing groups. for now, face_is_smooth is always true.
|
||||
if (face_is_smooth == n->faces[j].smooth) {
|
||||
for (int h = 0; h < 3; h++) {
|
||||
Vector3 vert_b = n->faces[j].vertices[h];
|
||||
if (vert_a == vert_b) {
|
||||
int curr_j = j * 3 + h;
|
||||
smooth_vertex[curr_vert] += smooth_faces[j];
|
||||
smooth_vertex[curr_j] += smooth_faces[i];
|
||||
// Skip the other 2 vertices as only one vertex of each face can connect with one vertex of other face.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
smooth_vertex[curr_vert].normalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector<ShapeUpdateSurface> surfaces;
|
||||
|
||||
surfaces.resize(face_count.size());
|
||||
|
|
@ -729,12 +647,19 @@ void CSGShape3D::update_shape() {
|
|||
|
||||
int last = surfaces[idx].last_added;
|
||||
|
||||
int face_pos_i = i * 3;
|
||||
Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
Vector3 v = n->faces[i].vertices[j];
|
||||
|
||||
Vector3 normal = smooth_vertex[face_pos_i + j];
|
||||
Vector3 normal = p.normal;
|
||||
|
||||
if (n->faces[i].smooth) {
|
||||
Vector3 *ptr = vec_map.getptr(v);
|
||||
if (ptr) {
|
||||
normal = ptr->normalized();
|
||||
}
|
||||
}
|
||||
|
||||
if (n->faces[i].invert) {
|
||||
normal = -normal;
|
||||
|
|
@ -803,8 +728,6 @@ void CSGShape3D::update_shape() {
|
|||
|
||||
set_base(root_mesh->get_rid());
|
||||
|
||||
update_gizmos();
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
_update_collision_faces();
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
|
@ -1030,19 +953,6 @@ void CSGShape3D::_validate_property(PropertyInfo &p_property) const {
|
|||
if (!Engine::get_singleton()->is_editor_hint()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_property.name == "smoothing_angle") {
|
||||
if (!autosmooth || (is_inside_tree() && !is_root_shape())) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_property.name == "autosmooth") {
|
||||
if (is_inside_tree() && !is_root_shape()) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_collision_prefixed = p_property.name.begins_with("collision_");
|
||||
if ((is_collision_prefixed || p_property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) {
|
||||
//hide collision if not root
|
||||
|
|
@ -1127,15 +1037,6 @@ void CSGShape3D::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("bake_static_mesh"), &CSGShape3D::bake_static_mesh);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_autosmooth", "autosmooth"), &CSGShape3D::set_autosmooth);
|
||||
ClassDB::bind_method(D_METHOD("is_autosmooth"), &CSGShape3D::is_autosmooth);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_smoothing_angle", "smoothing_angle"), &CSGShape3D::set_smoothing_angle);
|
||||
ClassDB::bind_method(D_METHOD("get_smoothing_angle"), &CSGShape3D::get_smoothing_angle);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autosmooth"), "set_autosmooth", "is_autosmooth");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "smoothing_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_smoothing_angle", "get_smoothing_angle");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_RANGE, "0.000001,1,0.000001,suffix:m", PROPERTY_USAGE_NONE), "set_snap", "get_snap");
|
||||
|
|
|
|||
|
|
@ -39,9 +39,8 @@
|
|||
#include "scene/resources/3d/concave_polygon_shape_3d.h"
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
|
||||
#include <thirdparty/misc/mikktspace.h>
|
||||
#include "thirdparty/misc/mikktspace.h"
|
||||
|
||||
class Mesh;
|
||||
class NavigationMesh;
|
||||
class NavigationMeshSourceGeometryData3D;
|
||||
|
||||
|
|
@ -68,9 +67,6 @@ private:
|
|||
bool last_visible = false;
|
||||
float snap = 0.001;
|
||||
|
||||
bool autosmooth = false;
|
||||
float smoothing_angle = 50.0;
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
bool use_collision = false;
|
||||
uint32_t collision_layer = 1;
|
||||
|
|
@ -162,12 +158,6 @@ public:
|
|||
void set_collision_priority(real_t p_priority);
|
||||
real_t get_collision_priority() const;
|
||||
|
||||
void set_autosmooth(bool p_smooth);
|
||||
bool is_autosmooth() const;
|
||||
|
||||
void set_smoothing_angle(const float p_angle);
|
||||
float get_smoothing_angle() const;
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void set_snap(float p_snap);
|
||||
float get_snap() const;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSGBox3D" inherits="CSGPrimitive3D" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="CSGBox3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A CSG Box shape.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSGCombiner3D" inherits="CSGShape3D" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="CSGCombiner3D" inherits="CSGShape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A CSG node that allows you to combine other CSG modifiers.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSGCylinder3D" inherits="CSGPrimitive3D" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="CSGCylinder3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A CSG Cylinder shape.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSGMesh3D" inherits="CSGPrimitive3D" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="CSGMesh3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A CSG Mesh shape that uses a mesh resource.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSGPolygon3D" inherits="CSGPrimitive3D" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="CSGPolygon3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Extrudes a 2D polygon shape to create a 3D mesh.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSGPrimitive3D" inherits="CSGShape3D" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="CSGPrimitive3D" inherits="CSGShape3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Base class for CSG primitives.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSGShape3D" inherits="GeometryInstance3D" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="CSGShape3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
The CSG base class.
|
||||
</brief_description>
|
||||
|
|
@ -74,10 +74,6 @@
|
|||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="autosmooth" type="bool" setter="set_autosmooth" getter="is_autosmooth" default="false">
|
||||
Enables automatic smoothing. This overrides any smoothing on the CSG node and instead uses [member smoothing_angle] to calculate normals based on the angle between faces.
|
||||
Children of a [CSGCombiner3D] node will be treated as a single mesh.
|
||||
</member>
|
||||
<member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents" default="true">
|
||||
Calculate tangents for the CSG shape which allows the use of normal and height maps. This is only applied on the root shape, this setting is ignored on any child. Setting this to [code]false[/code] can speed up shape generation slightly.
|
||||
</member>
|
||||
|
|
@ -95,10 +91,6 @@
|
|||
<member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape3D.Operation" default="0">
|
||||
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
|
||||
</member>
|
||||
<member name="smoothing_angle" type="float" setter="set_smoothing_angle" getter="get_smoothing_angle" default="50.0">
|
||||
When autosmooth is enabled, faces with an angle between them greater than this will be smoothed, while faces with a smaller angle will remain sharp.
|
||||
Note: An angle lower than 0.1 will cause all smoothing to be disabled, this can be used to increase performance.
|
||||
</member>
|
||||
<member name="snap" type="float" setter="set_snap" getter="get_snap" deprecated="The CSG library no longer uses snapping.">
|
||||
This property does nothing.
|
||||
</member>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSGSphere3D" inherits="CSGPrimitive3D" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="CSGSphere3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A CSG Sphere shape.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="CSGTorus3D" inherits="CSGPrimitive3D" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="CSGTorus3D" inherits="CSGPrimitive3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A CSG Torus shape.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include "csg_gizmos.h"
|
||||
|
||||
#include "core/math/geometry_3d.h"
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "editor/scene/3d/gizmos/gizmo_3d_helper.h"
|
||||
|
|
@ -42,7 +40,6 @@
|
|||
#include "scene/3d/physics/collision_shape_3d.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/menu_button.h"
|
||||
#include "scene/main/scene_tree.h"
|
||||
|
||||
void CSGShapeEditor::_node_removed(Node *p_node) {
|
||||
if (p_node == node) {
|
||||
|
|
@ -419,14 +416,17 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
|
|||
Ref<Material> handles_material = get_material("handles");
|
||||
|
||||
p_gizmo->add_lines(lines, material);
|
||||
p_gizmo->add_collision_segments(lines);
|
||||
|
||||
Ref<ArrayMesh> collision_mesh;
|
||||
collision_mesh.instantiate();
|
||||
Array collision_array;
|
||||
collision_array.resize(Mesh::ARRAY_MAX);
|
||||
collision_array[Mesh::ARRAY_VERTEX] = faces;
|
||||
collision_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, collision_array);
|
||||
p_gizmo->add_collision_triangles(collision_mesh->generate_triangle_mesh());
|
||||
if (cs->is_root_shape()) {
|
||||
Array csg_meshes = cs->get_meshes();
|
||||
if (csg_meshes.size() == 2) {
|
||||
Ref<Mesh> csg_mesh = csg_meshes[1];
|
||||
if (csg_mesh.is_valid()) {
|
||||
p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p_gizmo->is_selected()) {
|
||||
// Draw a translucent representation of the CSG node
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@
|
|||
|
||||
#include "csg_shape.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/csg_gizmos.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -30,10 +30,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../csg.h"
|
||||
#include "../csg_shape.h"
|
||||
|
||||
#include "scene/main/scene_tree.h"
|
||||
#include "scene/main/window.h"
|
||||
#include "tests/test_macros.h"
|
||||
|
||||
namespace TestCSG {
|
||||
|
|
|
|||
|
|
@ -164,8 +164,6 @@ enum DDSFormat {
|
|||
DDS_LUMINANCE,
|
||||
DDS_LUMINANCE_ALPHA,
|
||||
DDS_LUMINANCE_ALPHA_4,
|
||||
DDS_RG8,
|
||||
DDS_R8,
|
||||
DDS_MAX
|
||||
};
|
||||
|
||||
|
|
@ -225,6 +223,4 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = {
|
|||
{ "GRAYSCALE", false, 1, 1, Image::FORMAT_L8 },
|
||||
{ "GRAYSCALE_ALPHA", false, 1, 2, Image::FORMAT_LA8 },
|
||||
{ "GRAYSCALE_ALPHA_4", false, 1, 1, Image::FORMAT_LA8 },
|
||||
{ "RG8", false, 1, 2, Image::FORMAT_RG8 },
|
||||
{ "R8", false, 1, 1, Image::FORMAT_R8 },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@
|
|||
#include "image_saver_dds.h"
|
||||
#include "texture_loader_dds.h"
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
static Ref<ResourceFormatDDS> resource_loader_dds;
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@
|
|||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/image.h"
|
||||
#include "tests/core/config/test_project_settings.h"
|
||||
#include "tests/test_macros.h"
|
||||
#include "tests/test_utils.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/file_access_memory.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "scene/resources/image_texture.h"
|
||||
|
||||
DDSFormat _dxgi_to_dds_format(uint32_t p_dxgi_format) {
|
||||
|
|
@ -76,9 +75,7 @@ DDSFormat _dxgi_to_dds_format(uint32_t p_dxgi_format) {
|
|||
case DXGI_R32_FLOAT: {
|
||||
return DDS_R32F;
|
||||
}
|
||||
case DXGI_R8_UNORM: {
|
||||
return DDS_R8;
|
||||
}
|
||||
case DXGI_R8_UNORM:
|
||||
case DXGI_A8_UNORM: {
|
||||
return DDS_LUMINANCE;
|
||||
}
|
||||
|
|
@ -92,7 +89,7 @@ DDSFormat _dxgi_to_dds_format(uint32_t p_dxgi_format) {
|
|||
return DDS_R16I;
|
||||
}
|
||||
case DXGI_R8G8_UNORM: {
|
||||
return DDS_RG8;
|
||||
return DDS_LUMINANCE_ALPHA;
|
||||
}
|
||||
case DXGI_R9G9B9E5: {
|
||||
return DDS_RGB9E5;
|
||||
|
|
@ -651,10 +648,6 @@ static Vector<Ref<Image>> _dds_load_images_from_buffer(Ref<FileAccess> p_f, DDSF
|
|||
r_dds_format = DDS_BGRX8;
|
||||
} else if (format_rgb_bits == 32 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000) {
|
||||
r_dds_format = DDS_RGBX8;
|
||||
} else if (format_rgb_bits == 8 && format_red_mask == 0xff && format_green_mask == 0 && format_blue_mask == 0) {
|
||||
r_dds_format = DDS_R8;
|
||||
} else if (format_rgb_bits == 16 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0) {
|
||||
r_dds_format = DDS_RG8;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="ENetConnection" inherits="RefCounted" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="ENetConnection" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A wrapper class for an [url=http://enet.bespin.org/group__host.html]ENetHost[/url].
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="ENetMultiplayerPeer" inherits="MultiplayerPeer" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="ENetMultiplayerPeer" inherits="MultiplayerPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A MultiplayerPeer implementation using the [url=http://enet.bespin.org/index.html]ENet[/url] library.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="ENetPacketPeer" inherits="PacketPeer" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="ENetPacketPeer" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A wrapper class for an [url=http://enet.bespin.org/group__peer.html]ENetPeer[/url].
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
#include "core/io/compression.h"
|
||||
#include "core/io/ip.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/variant/typed_array.h"
|
||||
|
||||
void ENetConnection::broadcast(enet_uint8 p_channel, ENetPacket *p_packet) {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include "enet_multiplayer_peer.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
void ENetMultiplayerPeer::set_target_peer(int p_peer) {
|
||||
target_peer = p_peer;
|
||||
}
|
||||
|
|
@ -479,7 +477,7 @@ void ENetMultiplayerPeer::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_host"), &ENetMultiplayerPeer::get_host);
|
||||
ClassDB::bind_method(D_METHOD("get_peer", "id"), &ENetMultiplayerPeer::get_peer);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "host", PROPERTY_HINT_RESOURCE_TYPE, ENetConnection::get_class_static(), PROPERTY_USAGE_NONE), "", "get_host");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "host", PROPERTY_HINT_RESOURCE_TYPE, "ENetConnection", PROPERTY_USAGE_NONE), "", "get_host");
|
||||
}
|
||||
|
||||
ENetMultiplayerPeer::ENetMultiplayerPeer() {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "enet_connection.h"
|
||||
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "scene/main/multiplayer_peer.h"
|
||||
|
||||
#include <enet/enet.h>
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include "enet_packet_peer.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
void ENetPacketPeer::peer_disconnect(int p_data) {
|
||||
ERR_FAIL_NULL(peer);
|
||||
enet_peer_disconnect(peer, p_data);
|
||||
|
|
@ -184,9 +182,6 @@ int ENetPacketPeer::get_packet_flags() const {
|
|||
|
||||
void ENetPacketPeer::_on_disconnect() {
|
||||
if (peer) {
|
||||
#ifdef GODOT_ENET
|
||||
enet_peer_socket_destroy(peer);
|
||||
#endif
|
||||
peer->data = nullptr;
|
||||
}
|
||||
peer = nullptr;
|
||||
|
|
@ -261,9 +256,6 @@ void ENetPacketPeer::_bind_methods() {
|
|||
ENetPacketPeer::ENetPacketPeer(ENetPeer *p_peer) {
|
||||
peer = p_peer;
|
||||
peer->data = this;
|
||||
#ifdef GODOT_ENET
|
||||
enet_peer_socket_bind(peer);
|
||||
#endif
|
||||
}
|
||||
|
||||
ENetPacketPeer::~ENetPacketPeer() {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
#include "enet_packet_peer.h"
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
static bool enet_ok = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="EditorSceneFormatImporterFBX2GLTF" inherits="EditorSceneFormatImporter" api_type="editor" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="EditorSceneFormatImporterFBX2GLTF" inherits="EditorSceneFormatImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Importer for the [code].fbx[/code] scene file format.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="EditorSceneFormatImporterUFBX" inherits="EditorSceneFormatImporter" api_type="editor" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="EditorSceneFormatImporterUFBX" inherits="EditorSceneFormatImporter" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Import FBX files using the ufbx library.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="FBXDocument" inherits="GLTFDocument" api_type="core" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="FBXDocument" inherits="GLTFDocument" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Handles FBX documents.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="FBXState" inherits="GLTFState" api_type="core" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="FBXState" inherits="GLTFState" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
</brief_description>
|
||||
<description>
|
||||
|
|
|
|||
|
|
@ -30,12 +30,9 @@
|
|||
|
||||
#include "editor_scene_importer_fbx2gltf.h"
|
||||
|
||||
#include "editor_scene_importer_ufbx.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
#include "core/os/os.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "editor_scene_importer_ufbx.h"
|
||||
|
||||
#include "modules/gltf/gltf_document.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
#include "editor_scene_importer_fbx2gltf.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
|
||||
void EditorSceneFormatImporterUFBX::get_extensions(List<String> *r_extensions) const {
|
||||
r_extensions->push_back("fbx");
|
||||
|
|
|
|||
|
|
@ -30,14 +30,12 @@
|
|||
|
||||
#include "fbx_document.h"
|
||||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/crypto/crypto_core.h"
|
||||
#include "core/io/config_file.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/file_access_memory.h"
|
||||
#include "core/io/image.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/math/color.h"
|
||||
#include "scene/3d/bone_attachment_3d.h"
|
||||
#include "scene/3d/camera_3d.h"
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include "fbx_state.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
void FBXState::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_allow_geometry_helper_nodes"), &FBXState::get_allow_geometry_helper_nodes);
|
||||
ClassDB::bind_method(D_METHOD("set_allow_geometry_helper_nodes", "allow"), &FBXState::set_allow_geometry_helper_nodes);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@
|
|||
|
||||
#include "modules/gltf/gltf_defines.h"
|
||||
#include "modules/gltf/gltf_state.h"
|
||||
#include "modules/gltf/structures/gltf_skeleton.h"
|
||||
#include "modules/gltf/structures/gltf_skin.h"
|
||||
#include "modules/gltf/structures/gltf_texture.h"
|
||||
|
||||
#include <ufbx.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -30,17 +30,13 @@
|
|||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "../gltf/extensions/gltf_document_extension_convert_importer_mesh.h"
|
||||
#include "fbx_document.h"
|
||||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
#include "modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/editor_scene_importer_fbx2gltf.h"
|
||||
#include "editor/editor_scene_importer_ufbx.h"
|
||||
//
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "editor/editor_node.h"
|
||||
|
||||
|
|
@ -59,8 +55,8 @@ static void _editor_init() {
|
|||
#endif // TOOLS_ENABLED
|
||||
|
||||
#define FBX_REGISTER_DOCUMENT_EXTENSION(m_doc_ext_class) \
|
||||
Ref<m_doc_ext_class> extension_##m_doc_ext_class; \
|
||||
extension_##m_doc_ext_class.instantiate(); \
|
||||
Ref<m_doc_ext_class> extension_##m_doc_ext_class; \
|
||||
extension_##m_doc_ext_class.instantiate(); \
|
||||
FBXDocument::register_gltf_document_extension(extension_##m_doc_ext_class);
|
||||
|
||||
void initialize_fbx_module(ModuleInitializationLevel p_level) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,5 @@ if env.editor_build:
|
|||
|
||||
|
||||
if env["tests"]:
|
||||
# TODO: Handle test creation magic without needing to pass macro.
|
||||
env_gdscript.Append(CPPDEFINES=["TESTS_ENABLED"])
|
||||
env_gdscript.add_source_files(env.modules_sources, "./tests/*.cpp")
|
||||
|
|
|
|||
|
|
@ -11,10 +11,7 @@ def get_doc_classes():
|
|||
return [
|
||||
"@GDScript",
|
||||
"GDScript",
|
||||
"GDScriptLanguageProtocol",
|
||||
"GDScriptSyntaxHighlighter",
|
||||
"GDScriptTextDocument",
|
||||
"GDScriptWorkspace",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@
|
|||
- A constant from the [enum Variant.Type] enumeration, for example [constant TYPE_INT].
|
||||
- An [Object]-derived class which exists in [ClassDB], for example [Node].
|
||||
- A [Script] (you can use any class, including inner one).
|
||||
Unlike the right operand of the [code]is[/code] operator, [param type] can be a non-constant value. The [code]is[/code] operator supports more features (such as typed arrays and dictionaries). Use the operator instead of this method if you do not need to check the type dynamically.
|
||||
Unlike the right operand of the [code]is[/code] operator, [param type] can be a non-constant value. The [code]is[/code] operator supports more features (such as typed arrays). Use the operator instead of this method if you do not need to check the type dynamically.
|
||||
[b]Examples:[/b]
|
||||
[codeblock]
|
||||
print(is_instance_of(a, TYPE_INT))
|
||||
|
|
@ -142,7 +142,7 @@
|
|||
print(is_instance_of(a, MyClass.InnerClass))
|
||||
[/codeblock]
|
||||
[b]Note:[/b] If [param value] and/or [param type] are freed objects (see [method @GlobalScope.is_instance_valid]), or [param type] is not one of the above options, this method will raise a runtime error.
|
||||
See also [method @GlobalScope.typeof], [method Object.is_class], [method Object.get_script], [method Array.is_same_typed] (and other [Array] methods), [method Dictionary.is_same_typed] (and other [Dictionary] methods).
|
||||
See also [method @GlobalScope.typeof], [method type_exists], [method Array.is_same_typed] (and other [Array] methods).
|
||||
</description>
|
||||
</method>
|
||||
<method name="len">
|
||||
|
|
@ -266,7 +266,7 @@
|
|||
[/codeblock]
|
||||
</description>
|
||||
</method>
|
||||
<method name="type_exists" deprecated="Use [method ClassDB.class_exists] instead.">
|
||||
<method name="type_exists">
|
||||
<return type="bool" />
|
||||
<param index="0" name="type" type="StringName" />
|
||||
<description>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GDScript" inherits="Script" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="GDScript" inherits="Script" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A script implemented in the GDScript programming language.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GDScriptLanguageProtocol" inherits="JSONRPC" api_type="editor" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
GDScript language server.
|
||||
</brief_description>
|
||||
<description>
|
||||
Provides access to certain features that are implemented in the language server.
|
||||
[b]Note:[/b] This class is not a language server client that can be used to access LSP functionality. It only provides access to a limited set of features that is implemented using the same technical foundation as the language server.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="get_text_document" deprecated="[GDScriptTextDocument] is deprecated.">
|
||||
<return type="GDScriptTextDocument" />
|
||||
<description>
|
||||
Returns the language server's [GDScriptTextDocument] instance.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_workspace">
|
||||
<return type="GDScriptWorkspace" />
|
||||
<description>
|
||||
Returns the language server's [GDScriptWorkspace] instance.
|
||||
</description>
|
||||
</method>
|
||||
<method name="initialize" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Dictionary" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="initialized" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="void" />
|
||||
<param index="0" name="params" type="Variant" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_initialized" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if the language server was initialized by a language server client, [code]false[/code] otherwise.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_smart_resolve_enabled" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if the language server is providing the smart resolve feature, [code]false[/code] otherwise. The feature can be configured through the editor settings.
|
||||
</description>
|
||||
</method>
|
||||
<method name="notify_client" deprecated="Might result in unwanted side effects for connected clients.">
|
||||
<return type="void" />
|
||||
<param index="0" name="method" type="String" />
|
||||
<param index="1" name="params" type="Variant" default="null" />
|
||||
<param index="2" name="client_id" type="int" default="-1" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="on_client_connected" deprecated="Might result in unwanted side effects for connected clients.">
|
||||
<return type="int" enum="Error" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="on_client_disconnected" deprecated="Might result in unwanted side effects for connected clients.">
|
||||
<return type="void" />
|
||||
<param index="0" name="client_id" type="int" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GDScriptSyntaxHighlighter" inherits="EditorSyntaxHighlighter" api_type="editor" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<class name="GDScriptSyntaxHighlighter" inherits="EditorSyntaxHighlighter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
A GDScript syntax highlighter that can be used with [TextEdit] and [CodeEdit] nodes.
|
||||
</brief_description>
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GDScriptTextDocument" inherits="RefCounted" api_type="editor" deprecated="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Document related language server functionality.
|
||||
</brief_description>
|
||||
<description>
|
||||
Provides language server functionality related to documents.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="codeLens" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Array" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="colorPresentation" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Array" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="completion" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Array" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="declaration" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="definition" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Array" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="didChange" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="void" />
|
||||
<param index="0" name="params" type="Variant" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="didClose" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="void" />
|
||||
<param index="0" name="params" type="Variant" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="didOpen" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="void" />
|
||||
<param index="0" name="params" type="Variant" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="didSave" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="void" />
|
||||
<param index="0" name="params" type="Variant" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="documentLink" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Array" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="documentSymbol" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Array" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="foldingRange" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Array" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="hover" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="nativeSymbol" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="prepareRename" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="references" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Array" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="rename" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Dictionary" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="resolve" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Dictionary" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="show_native_symbol_in_editor" deprecated="Use [method ScriptEditor.goto_help] instead.">
|
||||
<return type="void" />
|
||||
<param index="0" name="symbol_id" type="String" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="signatureHelp" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="willSaveWaitUntil" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="void" />
|
||||
<param index="0" name="params" type="Variant" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GDScriptWorkspace" inherits="RefCounted" api_type="editor" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Workspace related language server functionality.
|
||||
</brief_description>
|
||||
<description>
|
||||
Provides language server functionality related to the workspace.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="apply_new_signal" deprecated="Might result in unwanted side effects for connected clients.">
|
||||
<return type="void" />
|
||||
<param index="0" name="obj" type="Object" />
|
||||
<param index="1" name="function" type="String" />
|
||||
<param index="2" name="args" type="PackedStringArray" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="didDeleteFiles" deprecated="Accessing LSP endpoints directly might lead to unwanted side effects. Connect to the server via TCP, like a regular language server client.">
|
||||
<return type="void" />
|
||||
<param index="0" name="params" type="Dictionary" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="generate_script_api">
|
||||
<return type="Dictionary" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Returns the interface of the script in a machine-readable format.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_file_path">
|
||||
<return type="String" />
|
||||
<param index="0" name="uri" type="String" />
|
||||
<description>
|
||||
Converts a URI to a file path.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_file_uri" qualifiers="const">
|
||||
<return type="String" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Converts a file path to a URI.
|
||||
</description>
|
||||
</method>
|
||||
<method name="parse_local_script" deprecated="Might result in unwanted side effects for connected clients.">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="parse_script" deprecated="Might result in unwanted side effects for connected clients.">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<param index="1" name="content" type="String" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="publish_diagnostics" deprecated="Might result in unwanted side effects for connected clients.">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
|
|
@ -33,7 +33,6 @@
|
|||
#include "../gdscript.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/doc_data.h"
|
||||
|
||||
HashMap<String, String> GDScriptDocGen::singletons;
|
||||
|
||||
|
|
@ -316,11 +315,6 @@ String GDScriptDocGen::docvalue_from_expression(const GDP::ExpressionNode *p_exp
|
|||
const GDP::IdentifierNode *id = static_cast<const GDP::IdentifierNode *>(p_expression);
|
||||
return id->name;
|
||||
} break;
|
||||
case GDP::Node::LAMBDA: {
|
||||
const GDP::LambdaNode *lambda = static_cast<const GDP::LambdaNode *>(p_expression);
|
||||
const GDP::IdentifierNode *id = lambda->function->identifier;
|
||||
return id != nullptr ? id->name : "<anonymous lambda>";
|
||||
} break;
|
||||
default: {
|
||||
// Nothing to do.
|
||||
} break;
|
||||
|
|
@ -439,9 +433,10 @@ void GDScriptDocGen::_generate_docs(GDScript *p_script, const GDP::ClassNode *p_
|
|||
method_doc.qualifiers += "static";
|
||||
}
|
||||
|
||||
if (func_name == "_init" || func_name == "_static_init") {
|
||||
if (func_name == "_init") {
|
||||
method_doc.return_type = "void";
|
||||
} else if (!m_func->get_datatype().is_variant()) {
|
||||
} else if (m_func->return_type) {
|
||||
// `m_func->return_type->get_datatype()` is a metatype.
|
||||
_doctype_from_gdtype(m_func->get_datatype(), method_doc.return_type, method_doc.return_enum, true);
|
||||
} else if (!m_func->body->has_return) {
|
||||
// If no `return` statement, then return type is `void`, not `Variant`.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include "../gdscript_parser.h"
|
||||
|
||||
#include "core/doc_data.h"
|
||||
|
||||
class GDScriptDocGen {
|
||||
using GDP = GDScriptParser;
|
||||
using GDType = GDP::DataType;
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@
|
|||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/core_constants.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "editor/themes/editor_theme_manager.h"
|
||||
#include "scene/gui/text_edit.h"
|
||||
|
||||
Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "editor/script/syntax_highlighters.h"
|
||||
#include "editor/script/script_editor_plugin.h"
|
||||
|
||||
class GDScriptSyntaxHighlighter : public EditorSyntaxHighlighter {
|
||||
GDCLASS(GDScriptSyntaxHighlighter, EditorSyntaxHighlighter)
|
||||
|
|
|
|||
|
|
@ -450,7 +450,6 @@ GDScriptEditorTranslationParserPlugin::GDScriptEditorTranslationParserPlugin() {
|
|||
first_arg_patterns.insert("add_radio_check_item");
|
||||
first_arg_patterns.insert("add_separator");
|
||||
first_arg_patterns.insert("add_submenu_item");
|
||||
first_arg_patterns.insert("add_submenu_node_item");
|
||||
|
||||
second_arg_patterns.insert("set_tab_title");
|
||||
second_arg_patterns.insert("add_icon_check_item");
|
||||
|
|
|
|||
|
|
@ -38,10 +38,6 @@
|
|||
#include "gdscript_tokenizer_buffer.h"
|
||||
#include "gdscript_warning.h"
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/gdscript_docgen.h"
|
||||
#endif
|
||||
|
|
@ -54,6 +50,7 @@
|
|||
#include "core/config/project_settings.h"
|
||||
#include "core/core_constants.h"
|
||||
#include "core/io/file_access.h"
|
||||
|
||||
#include "scene/resources/packed_scene.h"
|
||||
#include "scene/scene_string_names.h"
|
||||
|
||||
|
|
@ -227,17 +224,16 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
|
|||
ERR_FAIL_COND_V(_baseptr->native.is_null(), Variant());
|
||||
if (_baseptr->native.ptr()) {
|
||||
owner = _baseptr->native->instantiate();
|
||||
|
||||
RefCounted *r = Object::cast_to<RefCounted>(owner);
|
||||
if (r) {
|
||||
ref = Ref<RefCounted>(r);
|
||||
}
|
||||
} else {
|
||||
ref = memnew(RefCounted); // By default, no base means use reference.
|
||||
owner = ref.ptr();
|
||||
owner = memnew(RefCounted); //by default, no base means use reference
|
||||
}
|
||||
ERR_FAIL_NULL_V_MSG(owner, Variant(), "Can't inherit from a virtual class.");
|
||||
|
||||
RefCounted *r = Object::cast_to<RefCounted>(owner);
|
||||
if (r) {
|
||||
ref = Ref<RefCounted>(r);
|
||||
}
|
||||
|
||||
GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r_error);
|
||||
if (!instance) {
|
||||
if (ref.is_null()) {
|
||||
|
|
@ -648,7 +644,7 @@ void GDScript::_update_exports_down(bool p_base_exports_changed) {
|
|||
return;
|
||||
}
|
||||
|
||||
HashSet<ObjectID> copy(inheriters_cache); //might get modified
|
||||
HashSet<ObjectID> copy = inheriters_cache; //might get modified
|
||||
|
||||
for (const ObjectID &E : copy) {
|
||||
Object *id = ObjectDB::get_instance(E);
|
||||
|
|
@ -824,10 +820,10 @@ Error GDScript::reload(bool p_keep_state) {
|
|||
}
|
||||
if (err) {
|
||||
if (EngineDebugger::is_active()) {
|
||||
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().start_line, "Parser Error: " + parser.get_errors().front()->get().message);
|
||||
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
|
||||
}
|
||||
// TODO: Show all error messages.
|
||||
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().start_line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
|
||||
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
|
||||
reloading = false;
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
|
@ -837,12 +833,12 @@ Error GDScript::reload(bool p_keep_state) {
|
|||
|
||||
if (err) {
|
||||
if (EngineDebugger::is_active()) {
|
||||
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().start_line, "Parser Error: " + parser.get_errors().front()->get().message);
|
||||
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
|
||||
}
|
||||
|
||||
const List<GDScriptParser::ParserError>::Element *e = parser.get_errors().front();
|
||||
while (e != nullptr) {
|
||||
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().start_line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
|
||||
_err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
|
||||
e = e->next();
|
||||
}
|
||||
reloading = false;
|
||||
|
|
@ -931,6 +927,10 @@ const Variant GDScript::get_rpc_config() const {
|
|||
return rpc_config;
|
||||
}
|
||||
|
||||
void GDScript::unload_static() const {
|
||||
GDScriptCache::remove_script(fully_qualified_name);
|
||||
}
|
||||
|
||||
Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
|
||||
GDScript *top = this;
|
||||
while (top) {
|
||||
|
|
@ -945,19 +945,9 @@ Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int
|
|||
top = top->base.ptr();
|
||||
}
|
||||
|
||||
{
|
||||
Variant ret = Script::callp(p_method, p_args, p_argcount, r_error);
|
||||
if (r_error.error != Callable::CallError::CALL_ERROR_INVALID_METHOD) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
//none found, regular
|
||||
|
||||
if (native.is_valid()) {
|
||||
return native->callp(p_method, p_args, p_argcount, r_error);
|
||||
}
|
||||
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
|
||||
return Variant();
|
||||
return Script::callp(p_method, p_args, p_argcount, r_error);
|
||||
}
|
||||
|
||||
bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
|
|
@ -1105,15 +1095,7 @@ void GDScript::set_path(const String &p_path, bool p_take_over) {
|
|||
String old_path = path;
|
||||
path = p_path;
|
||||
path_valid = true;
|
||||
|
||||
String old_base = GDScript::canonicalize_path(old_path);
|
||||
if (!old_base.is_empty() && fully_qualified_name.begins_with(old_base)) {
|
||||
fully_qualified_name = GDScript::canonicalize_path(p_path) + fully_qualified_name.substr(old_base.length());
|
||||
}
|
||||
|
||||
if (is_root_script()) {
|
||||
GDScriptCache::move_script(old_path, p_path);
|
||||
}
|
||||
GDScriptCache::move_script(old_path, p_path);
|
||||
|
||||
for (KeyValue<StringName, Ref<GDScript>> &kv : subclasses) {
|
||||
kv.value->set_path(p_path, p_take_over);
|
||||
|
|
@ -2892,3 +2874,170 @@ Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_na
|
|||
}
|
||||
return Ref<GDScript>(Object::cast_to<GDScript>(obj));
|
||||
}
|
||||
|
||||
Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String &p_name) {
|
||||
{
|
||||
MutexLock lock(mutex);
|
||||
|
||||
SelfList<GDScript> *elem = script_list.first();
|
||||
while (elem) {
|
||||
GDScript *scr = elem->self();
|
||||
if (scr->fully_qualified_name == p_name) {
|
||||
return scr;
|
||||
}
|
||||
elem = elem->next();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<GDScript> scr;
|
||||
scr.instantiate();
|
||||
scr->fully_qualified_name = p_name;
|
||||
return scr;
|
||||
}
|
||||
|
||||
/*************** RESOURCE ***************/
|
||||
|
||||
Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
Error err;
|
||||
bool ignoring = p_cache_mode == CACHE_MODE_IGNORE || p_cache_mode == CACHE_MODE_IGNORE_DEEP;
|
||||
Ref<GDScript> scr = GDScriptCache::get_full_script(p_original_path, err, "", ignoring);
|
||||
|
||||
if (err && scr.is_valid()) {
|
||||
// If !scr.is_valid(), the error was likely from scr->load_source_code(), which already generates an error.
|
||||
ERR_PRINT_ED(vformat(R"(Failed to load script "%s" with error "%s".)", p_original_path, error_names[err]));
|
||||
}
|
||||
|
||||
if (r_error) {
|
||||
// Don't fail loading because of parsing error.
|
||||
*r_error = scr.is_valid() ? OK : err;
|
||||
}
|
||||
|
||||
return scr;
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("gd");
|
||||
p_extensions->push_back("gdc");
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
|
||||
return (p_type == "Script" || p_type == "GDScript");
|
||||
}
|
||||
|
||||
String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
|
||||
String el = p_path.get_extension().to_lower();
|
||||
if (el == "gd" || el == "gdc") {
|
||||
return "GDScript";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
|
||||
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ);
|
||||
ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'.");
|
||||
|
||||
String source = file->get_as_utf8_string();
|
||||
if (source.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GDScriptParser parser;
|
||||
if (OK != parser.parse(source, p_path, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const String &E : parser.get_dependencies()) {
|
||||
p_dependencies->push_back(E);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderGDScript::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
|
||||
Ref<GDScript> scr = ResourceLoader::load(p_path);
|
||||
if (scr.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const String source = scr->get_source_code();
|
||||
GDScriptTokenizerText tokenizer;
|
||||
tokenizer.set_source_code(source);
|
||||
GDScriptTokenizer::Token current = tokenizer.scan();
|
||||
while (current.type != GDScriptTokenizer::Token::TK_EOF) {
|
||||
if (!current.is_identifier()) {
|
||||
current = tokenizer.scan();
|
||||
continue;
|
||||
}
|
||||
|
||||
int insert_idx = 0;
|
||||
for (int i = 0; i < current.start_line - 1; i++) {
|
||||
insert_idx = source.find("\n", insert_idx) + 1;
|
||||
}
|
||||
// Insert the "cursor" character, needed for the lookup to work.
|
||||
const String source_with_cursor = source.insert(insert_idx + current.start_column, String::chr(0xFFFF));
|
||||
|
||||
ScriptLanguage::LookupResult result;
|
||||
if (scr->get_language()->lookup_code(source_with_cursor, current.get_identifier(), p_path, nullptr, result) == OK) {
|
||||
if (!result.class_name.is_empty() && ClassDB::class_exists(result.class_name)) {
|
||||
r_classes->insert(result.class_name);
|
||||
}
|
||||
|
||||
if (result.type == ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY) {
|
||||
PropertyInfo prop;
|
||||
if (ClassDB::get_property_info(result.class_name, result.class_member, &prop)) {
|
||||
if (!prop.class_name.is_empty() && ClassDB::class_exists(prop.class_name)) {
|
||||
r_classes->insert(prop.class_name);
|
||||
}
|
||||
if (!prop.hint_string.is_empty() && ClassDB::class_exists(prop.hint_string)) {
|
||||
r_classes->insert(prop.hint_string);
|
||||
}
|
||||
}
|
||||
} else if (result.type == ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD) {
|
||||
MethodInfo met;
|
||||
if (ClassDB::get_method_info(result.class_name, result.class_member, &met)) {
|
||||
if (!met.return_val.class_name.is_empty() && ClassDB::class_exists(met.return_val.class_name)) {
|
||||
r_classes->insert(met.return_val.class_name);
|
||||
}
|
||||
if (!met.return_val.hint_string.is_empty() && ClassDB::class_exists(met.return_val.hint_string)) {
|
||||
r_classes->insert(met.return_val.hint_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current = tokenizer.scan();
|
||||
}
|
||||
}
|
||||
|
||||
Error ResourceFormatSaverGDScript::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
|
||||
Ref<GDScript> sqscr = p_resource;
|
||||
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
|
||||
|
||||
String source = sqscr->get_source_code();
|
||||
|
||||
{
|
||||
Error err;
|
||||
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
|
||||
|
||||
file->store_string(source);
|
||||
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
|
||||
GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, true);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
|
||||
if (Object::cast_to<GDScript>(*p_resource)) {
|
||||
p_extensions->push_back("gd");
|
||||
}
|
||||
}
|
||||
|
||||
bool ResourceFormatSaverGDScript::recognize(const Ref<Resource> &p_resource) const {
|
||||
return Object::cast_to<GDScript>(*p_resource) != nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#include "core/debugger/engine_debugger.h"
|
||||
#include "core/debugger/script_debugger.h"
|
||||
#include "core/doc_data.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/templates/rb_set.h"
|
||||
|
||||
|
|
@ -337,6 +339,8 @@ public:
|
|||
|
||||
virtual const Variant get_rpc_config() const override;
|
||||
|
||||
void unload_static() const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; }
|
||||
#endif
|
||||
|
|
@ -596,6 +600,7 @@ public:
|
|||
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
|
||||
virtual Vector<ScriptTemplate> get_built_in_templates(const StringName &p_object) override;
|
||||
virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override;
|
||||
virtual Script *create_script() const override;
|
||||
virtual bool supports_builtin_mode() const override;
|
||||
virtual bool supports_documentation() const override;
|
||||
virtual bool can_inherit_from_file() const override { return true; }
|
||||
|
|
@ -654,6 +659,29 @@ public:
|
|||
void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass);
|
||||
Ref<GDScript> get_orphan_subclass(const String &p_qualified_name);
|
||||
|
||||
Ref<GDScript> get_script_by_fully_qualified_name(const String &p_name);
|
||||
|
||||
GDScriptLanguage();
|
||||
~GDScriptLanguage();
|
||||
};
|
||||
|
||||
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
|
||||
GDSOFTCLASS(ResourceFormatLoaderGDScript, ResourceFormatLoader);
|
||||
|
||||
public:
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override;
|
||||
virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override;
|
||||
};
|
||||
|
||||
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
|
||||
GDSOFTCLASS(ResourceFormatSaverGDScript, ResourceFormatSaver);
|
||||
|
||||
public:
|
||||
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
|
||||
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
|
||||
virtual bool recognize(const Ref<Resource> &p_resource) const override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,8 +113,6 @@ static GDScriptParser::DataType make_native_meta_type(const StringName &p_class_
|
|||
return type;
|
||||
}
|
||||
|
||||
// WARNING: Use this function **only** to create non-GDScript script metatypes. Otherwise, `check_type_compatibility()`
|
||||
// may return an incorrect result due to the assumption "A script type cannot be a subtype of a GDScript class".
|
||||
static GDScriptParser::DataType make_script_meta_type(const Ref<Script> &p_script) {
|
||||
GDScriptParser::DataType type;
|
||||
type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
|
||||
|
|
@ -1690,13 +1688,13 @@ void GDScriptAnalyzer::resolve_annotation(GDScriptParser::AnnotationNode *p_anno
|
|||
|
||||
reduce_expression(argument);
|
||||
|
||||
bool is_argument_value_reduced = false;
|
||||
Variant value = make_expression_reduced_value(argument, is_argument_value_reduced);
|
||||
if (!is_argument_value_reduced) {
|
||||
if (!argument->is_constant) {
|
||||
push_error(vformat(R"(Argument %d of annotation "%s" isn't a constant expression.)", i + 1, p_annotation->name), argument);
|
||||
return;
|
||||
}
|
||||
|
||||
Variant value = argument->reduced_value;
|
||||
|
||||
if (value.get_type() != argument_info.type) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (argument_info.type == Variant::INT && value.get_type() == Variant::FLOAT) {
|
||||
|
|
@ -1875,9 +1873,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
|
|||
if (!p_is_lambda && get_function_signature(p_function, false, base_type, function_name, parent_return_type, parameters_types, default_par_count, method_flags, &native_base)) {
|
||||
bool valid = p_function->is_static == method_flags.has_flag(METHOD_FLAG_STATIC);
|
||||
|
||||
if (p_function->return_type == nullptr) {
|
||||
p_function->set_datatype(parent_return_type);
|
||||
} else {
|
||||
if (p_function->return_type != nullptr) {
|
||||
// Check return type covariance.
|
||||
GDScriptParser::DataType return_type = p_function->get_datatype();
|
||||
if (return_type.is_variant()) {
|
||||
|
|
@ -2055,7 +2051,7 @@ void GDScriptAnalyzer::decide_suite_type(GDScriptParser::Node *p_suite, GDScript
|
|||
}
|
||||
}
|
||||
|
||||
void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite, bool p_is_root) {
|
||||
void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) {
|
||||
for (int i = 0; i < p_suite->statements.size(); i++) {
|
||||
GDScriptParser::Node *stmt = p_suite->statements[i];
|
||||
// Apply annotations.
|
||||
|
|
@ -2064,7 +2060,7 @@ void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite, bool p_
|
|||
E->apply(parser, stmt, nullptr); // TODO: Provide `p_class`.
|
||||
}
|
||||
|
||||
resolve_node(stmt, p_is_root);
|
||||
resolve_node(stmt);
|
||||
resolve_pending_lambda_bodies();
|
||||
decide_suite_type(p_suite, stmt);
|
||||
}
|
||||
|
|
@ -2260,7 +2256,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
|
|||
GDScriptParser::DataType list_type;
|
||||
|
||||
if (p_for->list) {
|
||||
reduce_expression(p_for->list);
|
||||
resolve_node(p_for->list, false);
|
||||
|
||||
bool is_range = false;
|
||||
if (p_for->list->type == GDScriptParser::Node::CALL) {
|
||||
|
|
@ -2377,7 +2373,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
|
|||
}
|
||||
|
||||
void GDScriptAnalyzer::resolve_while(GDScriptParser::WhileNode *p_while) {
|
||||
reduce_expression(p_while->condition);
|
||||
resolve_node(p_while->condition, false);
|
||||
|
||||
resolve_suite(p_while->loop);
|
||||
p_while->set_datatype(p_while->loop->get_datatype());
|
||||
}
|
||||
|
|
@ -2426,7 +2423,7 @@ void GDScriptAnalyzer::resolve_match_branch(GDScriptParser::MatchBranchNode *p_m
|
|||
}
|
||||
|
||||
if (p_match_branch->guard_body) {
|
||||
resolve_suite(p_match_branch->guard_body, false);
|
||||
resolve_suite(p_match_branch->guard_body);
|
||||
}
|
||||
|
||||
resolve_suite(p_match_branch->block);
|
||||
|
|
@ -2515,22 +2512,19 @@ void GDScriptAnalyzer::resolve_match_pattern(GDScriptParser::PatternNode *p_matc
|
|||
}
|
||||
|
||||
void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
|
||||
const bool has_expected_type = parser->current_function != nullptr;
|
||||
const GDScriptParser::DataType expected_type = has_expected_type ? parser->current_function->get_datatype() : GDScriptParser::DataType();
|
||||
|
||||
GDScriptParser::DataType result;
|
||||
|
||||
if (p_return->return_value == nullptr) {
|
||||
// Return type is `null` by default.
|
||||
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
|
||||
result.kind = GDScriptParser::DataType::BUILTIN;
|
||||
result.builtin_type = Variant::NIL;
|
||||
result.is_constant = true;
|
||||
} else {
|
||||
const bool is_void_function = has_expected_type && expected_type.is_hard_type() && expected_type.kind == GDScriptParser::DataType::BUILTIN && expected_type.builtin_type == Variant::NIL;
|
||||
const bool is_call = p_return->return_value->type == GDScriptParser::Node::CALL;
|
||||
GDScriptParser::DataType expected_type;
|
||||
bool has_expected_type = parser->current_function != nullptr;
|
||||
if (has_expected_type) {
|
||||
expected_type = parser->current_function->get_datatype();
|
||||
}
|
||||
|
||||
if (p_return->return_value != nullptr) {
|
||||
bool is_void_function = has_expected_type && expected_type.is_hard_type() && expected_type.kind == GDScriptParser::DataType::BUILTIN && expected_type.builtin_type == Variant::NIL;
|
||||
bool is_call = p_return->return_value->type == GDScriptParser::Node::CALL;
|
||||
if (is_void_function && is_call) {
|
||||
// Pretend the call is a root expression to allow those that are `void`.
|
||||
// Pretend the call is a root expression to allow those that are "void".
|
||||
reduce_call(static_cast<GDScriptParser::CallNode *>(p_return->return_value), false, true);
|
||||
} else {
|
||||
reduce_expression(p_return->return_value);
|
||||
|
|
@ -2564,30 +2558,28 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
|
|||
}
|
||||
result = p_return->return_value->get_datatype();
|
||||
}
|
||||
} else {
|
||||
// Return type is null by default.
|
||||
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
|
||||
result.kind = GDScriptParser::DataType::BUILTIN;
|
||||
result.builtin_type = Variant::NIL;
|
||||
result.is_constant = true;
|
||||
}
|
||||
|
||||
if (has_expected_type && !expected_type.is_variant() && expected_type.is_hard_type()) {
|
||||
if (has_expected_type && !expected_type.is_variant()) {
|
||||
if (result.is_variant() || !result.is_hard_type()) {
|
||||
p_return->use_conversion = true;
|
||||
mark_node_unsafe(p_return);
|
||||
if (!is_type_compatible(expected_type, result, true, p_return)) {
|
||||
downgrade_node_type_source(p_return);
|
||||
}
|
||||
} else if (!is_type_compatible(expected_type, result, true, p_return)) {
|
||||
if (is_type_compatible(result, expected_type)) {
|
||||
p_return->use_conversion = true;
|
||||
mark_node_unsafe(p_return);
|
||||
} else {
|
||||
mark_node_unsafe(p_return);
|
||||
if (!is_type_compatible(result, expected_type)) {
|
||||
push_error(vformat(R"(Cannot return value of type "%s" because the function return type is "%s".)", result.to_string(), expected_type.to_string()), p_return);
|
||||
}
|
||||
} else {
|
||||
if (!is_type_compatible(expected_type, result)) {
|
||||
p_return->use_conversion = true;
|
||||
}
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
|
||||
parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
|
||||
}
|
||||
} else if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
|
||||
parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
}
|
||||
|
|
@ -2887,7 +2879,8 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
|
|||
if (id_type.is_hard_type()) {
|
||||
switch (id_type.kind) {
|
||||
case GDScriptParser::DataType::BUILTIN:
|
||||
need_warn = !Variant::is_type_shared(id_type.builtin_type);
|
||||
// TODO: Change `Variant::is_type_shared()` to include packed arrays?
|
||||
need_warn = !Variant::is_type_shared(id_type.builtin_type) && id_type.builtin_type < Variant::PACKED_BYTE_ARRAY;
|
||||
break;
|
||||
case GDScriptParser::DataType::ENUM:
|
||||
need_warn = true;
|
||||
|
|
@ -3120,10 +3113,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
|
|||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
if (p_binary_op->left_operand->is_constant &&
|
||||
p_binary_op->right_operand->is_constant &&
|
||||
!p_binary_op->left_operand->reduced_value.is_shared() &&
|
||||
!p_binary_op->right_operand->reduced_value.is_shared()) {
|
||||
if (p_binary_op->left_operand->is_constant && p_binary_op->right_operand->is_constant) {
|
||||
p_binary_op->is_constant = true;
|
||||
if (p_binary_op->variant_op < Variant::OP_MAX) {
|
||||
bool valid = false;
|
||||
|
|
@ -3267,9 +3257,30 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
call_type.kind = GDScriptParser::DataType::BUILTIN;
|
||||
call_type.builtin_type = builtin_type;
|
||||
|
||||
// Reference types are not suited for compile-time construction.
|
||||
// Because in this case they would be the same reference in all constructed values.
|
||||
if (all_is_constant && !Variant::is_type_shared(builtin_type)) {
|
||||
bool safe_to_fold = true;
|
||||
switch (builtin_type) {
|
||||
// Those are stored by reference so not suited for compile-time construction.
|
||||
// Because in this case they would be the same reference in all constructed values.
|
||||
case Variant::OBJECT:
|
||||
case Variant::DICTIONARY:
|
||||
case Variant::ARRAY:
|
||||
case Variant::PACKED_BYTE_ARRAY:
|
||||
case Variant::PACKED_INT32_ARRAY:
|
||||
case Variant::PACKED_INT64_ARRAY:
|
||||
case Variant::PACKED_FLOAT32_ARRAY:
|
||||
case Variant::PACKED_FLOAT64_ARRAY:
|
||||
case Variant::PACKED_STRING_ARRAY:
|
||||
case Variant::PACKED_VECTOR2_ARRAY:
|
||||
case Variant::PACKED_VECTOR3_ARRAY:
|
||||
case Variant::PACKED_COLOR_ARRAY:
|
||||
case Variant::PACKED_VECTOR4_ARRAY:
|
||||
safe_to_fold = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (all_is_constant && safe_to_fold) {
|
||||
// Construct here.
|
||||
Vector<const Variant *> args;
|
||||
for (int i = 0; i < p_call->arguments.size(); i++) {
|
||||
|
|
@ -5201,9 +5212,9 @@ void GDScriptAnalyzer::reduce_type_test(GDScriptParser::TypeTestNode *p_type_tes
|
|||
p_type_test->is_constant = true;
|
||||
p_type_test->reduced_value = false;
|
||||
|
||||
if (!is_type_compatible_strict_collections(test_type, operand_type)) {
|
||||
if (!is_type_compatible(test_type, operand_type)) {
|
||||
push_error(vformat(R"(Expression is of type "%s" so it can't be of type "%s".)", operand_type.to_string(), test_type.to_string()), p_type_test->operand);
|
||||
} else if (is_type_compatible_strict_collections(test_type, type_from_variant(p_type_test->operand->reduced_value, p_type_test->operand))) {
|
||||
} else if (is_type_compatible(test_type, type_from_variant(p_type_test->operand->reduced_value, p_type_test->operand))) {
|
||||
p_type_test->reduced_value = test_type.builtin_type != Variant::OBJECT || !p_type_test->operand->reduced_value.is_null();
|
||||
}
|
||||
|
||||
|
|
@ -5253,33 +5264,25 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
|
|||
p_unary_op->set_datatype(result);
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::ExpressionNode *p_expression, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::ExpressionNode *p_expression, bool &is_reduced) {
|
||||
if (p_expression == nullptr) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
if (p_expression->is_constant) {
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return p_expression->reduced_value;
|
||||
}
|
||||
|
||||
switch (p_expression->type) {
|
||||
case GDScriptParser::Node::ARRAY:
|
||||
return make_array_reduced_value(static_cast<GDScriptParser::ArrayNode *>(p_expression), r_is_reduced);
|
||||
return make_array_reduced_value(static_cast<GDScriptParser::ArrayNode *>(p_expression), is_reduced);
|
||||
case GDScriptParser::Node::DICTIONARY:
|
||||
return make_dictionary_reduced_value(static_cast<GDScriptParser::DictionaryNode *>(p_expression), r_is_reduced);
|
||||
return make_dictionary_reduced_value(static_cast<GDScriptParser::DictionaryNode *>(p_expression), is_reduced);
|
||||
case GDScriptParser::Node::SUBSCRIPT:
|
||||
return make_subscript_reduced_value(static_cast<GDScriptParser::SubscriptNode *>(p_expression), r_is_reduced);
|
||||
return make_subscript_reduced_value(static_cast<GDScriptParser::SubscriptNode *>(p_expression), is_reduced);
|
||||
case GDScriptParser::Node::CALL:
|
||||
return make_call_reduced_value(static_cast<GDScriptParser::CallNode *>(p_expression), r_is_reduced);
|
||||
case GDScriptParser::Node::BINARY_OPERATOR:
|
||||
return make_binary_op_reduced_value(static_cast<GDScriptParser::BinaryOpNode *>(p_expression), r_is_reduced);
|
||||
case GDScriptParser::Node::TERNARY_OPERATOR:
|
||||
return make_ternary_op_reduced_value(static_cast<GDScriptParser::TernaryOpNode *>(p_expression), r_is_reduced);
|
||||
case GDScriptParser::Node::CAST:
|
||||
return make_cast_reduced_value(static_cast<GDScriptParser::CastNode *>(p_expression), r_is_reduced);
|
||||
case GDScriptParser::Node::TYPE_TEST:
|
||||
return make_type_test_reduced_value(static_cast<GDScriptParser::TypeTestNode *>(p_expression), r_is_reduced);
|
||||
return make_call_reduced_value(static_cast<GDScriptParser::CallNode *>(p_expression), is_reduced);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -5287,7 +5290,7 @@ Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::Expressi
|
|||
return Variant();
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_array_reduced_value(GDScriptParser::ArrayNode *p_array, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_array_reduced_value(GDScriptParser::ArrayNode *p_array, bool &is_reduced) {
|
||||
Array array = p_array->get_datatype().has_container_element_type(0) ? make_array_from_element_datatype(p_array->get_datatype().get_container_element_type(0)) : Array();
|
||||
|
||||
array.resize(p_array->elements.size());
|
||||
|
|
@ -5305,11 +5308,11 @@ Variant GDScriptAnalyzer::make_array_reduced_value(GDScriptParser::ArrayNode *p_
|
|||
|
||||
array.make_read_only();
|
||||
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return array;
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_dictionary_reduced_value(GDScriptParser::DictionaryNode *p_dictionary, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_dictionary_reduced_value(GDScriptParser::DictionaryNode *p_dictionary, bool &is_reduced) {
|
||||
Dictionary dictionary = p_dictionary->get_datatype().has_container_element_types()
|
||||
? make_dictionary_from_element_datatype(p_dictionary->get_datatype().get_container_element_type_or_variant(0), p_dictionary->get_datatype().get_container_element_type_or_variant(1))
|
||||
: Dictionary();
|
||||
|
|
@ -5334,11 +5337,11 @@ Variant GDScriptAnalyzer::make_dictionary_reduced_value(GDScriptParser::Dictiona
|
|||
|
||||
dictionary.make_read_only();
|
||||
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::SubscriptNode *p_subscript, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::SubscriptNode *p_subscript, bool &is_reduced) {
|
||||
if (p_subscript->base == nullptr || p_subscript->index == nullptr) {
|
||||
return Variant();
|
||||
}
|
||||
|
|
@ -5353,7 +5356,7 @@ Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::Subscript
|
|||
bool is_valid = false;
|
||||
Variant value = base_value.get_named(p_subscript->attribute->name, is_valid);
|
||||
if (is_valid) {
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return value;
|
||||
} else {
|
||||
return Variant();
|
||||
|
|
@ -5368,7 +5371,7 @@ Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::Subscript
|
|||
bool is_valid = false;
|
||||
Variant value = base_value.get(index_value, &is_valid);
|
||||
if (is_valid) {
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return value;
|
||||
} else {
|
||||
return Variant();
|
||||
|
|
@ -5376,7 +5379,7 @@ Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::Subscript
|
|||
}
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_call_reduced_value(GDScriptParser::CallNode *p_call, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_call_reduced_value(GDScriptParser::CallNode *p_call, bool &is_reduced) {
|
||||
if (p_call->get_callee_type() == GDScriptParser::Node::IDENTIFIER) {
|
||||
Variant::Type type = Variant::NIL;
|
||||
if (p_call->function_name == SNAME("Array")) {
|
||||
|
|
@ -5404,6 +5407,7 @@ Variant GDScriptAnalyzer::make_call_reduced_value(GDScriptParser::CallNode *p_ca
|
|||
Callable::CallError ce;
|
||||
Variant::construct(type, result, argptrs, args.size(), ce);
|
||||
if (ce.error) {
|
||||
push_error(vformat(R"(Failed to construct "%s".)", Variant::get_type_name(type)), p_call);
|
||||
return Variant();
|
||||
}
|
||||
|
||||
|
|
@ -5415,146 +5419,13 @@ Variant GDScriptAnalyzer::make_call_reduced_value(GDScriptParser::CallNode *p_ca
|
|||
dictionary.make_read_only();
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
return Variant();
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_binary_op_reduced_value(GDScriptParser::BinaryOpNode *p_binary_op, bool &r_is_reduced) {
|
||||
if (p_binary_op->variant_op == Variant::OP_MAX) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool is_left_op_value_reduced = false;
|
||||
Variant left_op_value = make_expression_reduced_value(p_binary_op->left_operand, is_left_op_value_reduced);
|
||||
if (!is_left_op_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool is_right_op_value_reduced = false;
|
||||
Variant right_op_value = make_expression_reduced_value(p_binary_op->right_operand, is_right_op_value_reduced);
|
||||
if (!is_right_op_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
Variant result;
|
||||
bool valid = false;
|
||||
Variant::evaluate(p_binary_op->variant_op, left_op_value, right_op_value, result, valid);
|
||||
if (!valid) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
if (result.get_type() == Variant::ARRAY) {
|
||||
Array array = result;
|
||||
array.make_read_only();
|
||||
} else if (result.get_type() == Variant::DICTIONARY) {
|
||||
Dictionary dictionary = result;
|
||||
dictionary.make_read_only();
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_ternary_op_reduced_value(GDScriptParser::TernaryOpNode *p_ternary_op, bool &r_is_reduced) {
|
||||
bool is_condition_value_reduced = false;
|
||||
Variant condition_value = make_expression_reduced_value(p_ternary_op->condition, is_condition_value_reduced);
|
||||
if (!is_condition_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool is_true_expr_value_reduced = false;
|
||||
Variant true_expr_value = make_expression_reduced_value(p_ternary_op->true_expr, is_true_expr_value_reduced);
|
||||
if (!is_true_expr_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool is_false_expr_value_reduced = false;
|
||||
Variant false_expr_value = make_expression_reduced_value(p_ternary_op->false_expr, is_false_expr_value_reduced);
|
||||
if (!is_false_expr_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
return condition_value.booleanize() ? true_expr_value : false_expr_value;
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_cast_reduced_value(GDScriptParser::CastNode *p_cast, bool &r_is_reduced) {
|
||||
bool is_operand_value_reduced = false;
|
||||
Variant operand_value = make_expression_reduced_value(p_cast->operand, is_operand_value_reduced);
|
||||
if (!is_operand_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
GDScriptParser::DataType cast_type = type_from_metatype(resolve_datatype(p_cast->cast_type));
|
||||
|
||||
if (!cast_type.is_set()) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
if (cast_type.is_variant()) {
|
||||
r_is_reduced = true;
|
||||
return operand_value;
|
||||
}
|
||||
|
||||
if (cast_type.kind == GDScriptParser::DataType::BUILTIN || cast_type.kind == GDScriptParser::DataType::ENUM) {
|
||||
Variant result;
|
||||
const Variant *argptr = &operand_value;
|
||||
Callable::CallError ce;
|
||||
Variant::construct(cast_type.builtin_type, result, &argptr, 1, ce);
|
||||
if (ce.error) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
if (result.get_type() == Variant::ARRAY) {
|
||||
Array array = cast_type.has_container_element_type(0) ? make_array_from_element_datatype(cast_type.get_container_element_type(0)) : Array();
|
||||
array.assign(result);
|
||||
array.make_read_only();
|
||||
result = array;
|
||||
} else if (result.get_type() == Variant::DICTIONARY) {
|
||||
Dictionary dictionary = cast_type.has_container_element_types()
|
||||
? make_dictionary_from_element_datatype(cast_type.get_container_element_type_or_variant(0), cast_type.get_container_element_type_or_variant(1))
|
||||
: Dictionary();
|
||||
dictionary.assign(result);
|
||||
dictionary.make_read_only();
|
||||
result = dictionary;
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
return Variant();
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_type_test_reduced_value(GDScriptParser::TypeTestNode *p_type_test, bool &r_is_reduced) {
|
||||
bool is_operand_value_reduced = false;
|
||||
Variant operand_value = make_expression_reduced_value(p_type_test->operand, is_operand_value_reduced);
|
||||
if (!is_operand_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
GDScriptParser::DataType test_type = type_from_metatype(p_type_test->test_type->get_datatype());
|
||||
if (!test_type.is_set()) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
GDScriptParser::DataType operand_type = type_from_variant(operand_value, p_type_test->operand);
|
||||
if (!operand_type.is_set()) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
if (is_type_compatible_strict_collections(test_type, operand_type)) {
|
||||
result = test_type.builtin_type != Variant::OBJECT || !operand_value.is_null();
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
Array GDScriptAnalyzer::make_array_from_element_datatype(const GDScriptParser::DataType &p_element_datatype, const GDScriptParser::Node *p_source_node) {
|
||||
Array array;
|
||||
|
||||
|
|
@ -5652,57 +5523,6 @@ Variant GDScriptAnalyzer::make_variable_default_value(GDScriptParser::VariableNo
|
|||
return result;
|
||||
}
|
||||
|
||||
GDScriptParser::DataType GDScriptAnalyzer::type_from_script(const Ref<Script> &p_script, const GDScriptParser::Node *p_source, bool p_is_meta_type) {
|
||||
ERR_FAIL_COND_V(!p_script.is_valid(), GDScriptParser::DataType());
|
||||
|
||||
GDScriptParser::DataType result;
|
||||
result.is_constant = true;
|
||||
result.kind = GDScriptParser::DataType::NATIVE;
|
||||
result.builtin_type = Variant::OBJECT;
|
||||
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; // Constant has explicit type.
|
||||
result.is_meta_type = p_is_meta_type;
|
||||
|
||||
Ref<GDScript> gds = p_script;
|
||||
if (gds.is_valid()) {
|
||||
// This might be an inner class, so we want to get the parser for the root.
|
||||
// But still get the inner class from that tree.
|
||||
String script_path = gds->get_script_path();
|
||||
Ref<GDScriptParserRef> ref = parser->get_depended_parser_for(script_path);
|
||||
if (ref.is_null()) {
|
||||
push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
|
||||
GDScriptParser::DataType error_type;
|
||||
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||
return error_type;
|
||||
}
|
||||
Error err = ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
|
||||
GDScriptParser::ClassNode *found = nullptr;
|
||||
if (err == OK) {
|
||||
found = ref->get_parser()->find_class(gds->fully_qualified_name);
|
||||
if (found != nullptr) {
|
||||
err = resolve_class_inheritance(found, p_source);
|
||||
}
|
||||
}
|
||||
if (err || found == nullptr) {
|
||||
push_error(vformat(R"(Could not resolve script "%s".)", script_path), p_source);
|
||||
GDScriptParser::DataType error_type;
|
||||
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||
return error_type;
|
||||
}
|
||||
|
||||
result.kind = GDScriptParser::DataType::CLASS;
|
||||
result.native_type = found->get_datatype().native_type;
|
||||
result.class_type = found;
|
||||
result.script_path = ref->get_parser()->script_path;
|
||||
} else {
|
||||
result.kind = GDScriptParser::DataType::SCRIPT;
|
||||
result.native_type = p_script->get_instance_base_type();
|
||||
result.script_path = p_script->get_path();
|
||||
}
|
||||
result.script_type = p_script;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) {
|
||||
GDScriptParser::DataType result;
|
||||
result.is_constant = true;
|
||||
|
|
@ -5713,7 +5533,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
|
|||
if (p_value.get_type() == Variant::ARRAY) {
|
||||
const Array &array = p_value;
|
||||
if (array.get_typed_script()) {
|
||||
result.set_container_element_type(0, type_from_metatype(type_from_script(array.get_typed_script(), p_source, true)));
|
||||
result.set_container_element_type(0, type_from_metatype(make_script_meta_type(array.get_typed_script())));
|
||||
} else if (array.get_typed_class_name()) {
|
||||
result.set_container_element_type(0, type_from_metatype(make_native_meta_type(array.get_typed_class_name())));
|
||||
} else if (array.get_typed_builtin() != Variant::NIL) {
|
||||
|
|
@ -5722,14 +5542,14 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
|
|||
} else if (p_value.get_type() == Variant::DICTIONARY) {
|
||||
const Dictionary &dict = p_value;
|
||||
if (dict.get_typed_key_script()) {
|
||||
result.set_container_element_type(0, type_from_metatype(type_from_script(dict.get_typed_key_script(), p_source, true)));
|
||||
result.set_container_element_type(0, type_from_metatype(make_script_meta_type(dict.get_typed_key_script())));
|
||||
} else if (dict.get_typed_key_class_name()) {
|
||||
result.set_container_element_type(0, type_from_metatype(make_native_meta_type(dict.get_typed_key_class_name())));
|
||||
} else if (dict.get_typed_key_builtin() != Variant::NIL) {
|
||||
result.set_container_element_type(0, type_from_metatype(make_builtin_meta_type((Variant::Type)dict.get_typed_key_builtin())));
|
||||
}
|
||||
if (dict.get_typed_value_script()) {
|
||||
result.set_container_element_type(1, type_from_metatype(type_from_script(dict.get_typed_value_script(), p_source, true)));
|
||||
result.set_container_element_type(1, type_from_metatype(make_script_meta_type(dict.get_typed_value_script())));
|
||||
} else if (dict.get_typed_value_class_name()) {
|
||||
result.set_container_element_type(1, type_from_metatype(make_native_meta_type(dict.get_typed_value_class_name())));
|
||||
} else if (dict.get_typed_value_builtin() != Variant::NIL) {
|
||||
|
|
@ -5746,16 +5566,50 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
|
|||
result.native_type = obj->get_class_name();
|
||||
|
||||
Ref<Script> scr = p_value; // Check if value is a script itself.
|
||||
bool is_meta_type;
|
||||
if (scr.is_valid()) {
|
||||
is_meta_type = true;
|
||||
result.is_meta_type = true;
|
||||
} else {
|
||||
is_meta_type = false;
|
||||
result.is_meta_type = false;
|
||||
scr = obj->get_script();
|
||||
}
|
||||
|
||||
if (scr.is_valid()) {
|
||||
result = type_from_script(scr, p_source, is_meta_type);
|
||||
Ref<GDScript> gds = scr;
|
||||
if (gds.is_valid()) {
|
||||
// This might be an inner class, so we want to get the parser for the root.
|
||||
// But still get the inner class from that tree.
|
||||
String script_path = gds->get_script_path();
|
||||
Ref<GDScriptParserRef> ref = parser->get_depended_parser_for(script_path);
|
||||
if (ref.is_null()) {
|
||||
push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
|
||||
GDScriptParser::DataType error_type;
|
||||
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||
return error_type;
|
||||
}
|
||||
Error err = ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
|
||||
GDScriptParser::ClassNode *found = nullptr;
|
||||
if (err == OK) {
|
||||
found = ref->get_parser()->find_class(gds->fully_qualified_name);
|
||||
if (found != nullptr) {
|
||||
err = resolve_class_inheritance(found, p_source);
|
||||
}
|
||||
}
|
||||
if (err || found == nullptr) {
|
||||
push_error(vformat(R"(Could not resolve script "%s".)", script_path), p_source);
|
||||
GDScriptParser::DataType error_type;
|
||||
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||
return error_type;
|
||||
}
|
||||
|
||||
result.kind = GDScriptParser::DataType::CLASS;
|
||||
result.native_type = found->get_datatype().native_type;
|
||||
result.class_type = found;
|
||||
result.script_path = ref->get_parser()->script_path;
|
||||
} else {
|
||||
result.kind = GDScriptParser::DataType::SCRIPT;
|
||||
result.native_type = scr->get_instance_base_type();
|
||||
result.script_path = scr->get_path();
|
||||
}
|
||||
result.script_type = scr;
|
||||
} else {
|
||||
result.kind = GDScriptParser::DataType::NATIVE;
|
||||
if (result.native_type == GDScriptNativeClass::get_class_static()) {
|
||||
|
|
@ -6296,21 +6150,6 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
|
|||
return check_type_compatibility(p_target, p_source, p_allow_implicit_conversion, p_source_node);
|
||||
}
|
||||
|
||||
// NOTE:`is_type_compatible()` considers typed arrays/dictionaries compatible with untyped ones (but the operation is unsafe).
|
||||
// However, in the case of constant expressions, this leads to incorrect results.
|
||||
bool GDScriptAnalyzer::is_type_compatible_strict_collections(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source) {
|
||||
if (p_target.builtin_type == Variant::ARRAY && p_source.builtin_type == Variant::ARRAY) {
|
||||
if (p_target.has_container_element_type(0) && !p_source.has_container_element_type(0)) {
|
||||
return false;
|
||||
}
|
||||
} else if (p_target.builtin_type == Variant::DICTIONARY && p_source.builtin_type == Variant::DICTIONARY) {
|
||||
if (p_target.has_container_element_types() && !p_source.has_container_element_types()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return is_type_compatible(p_target, p_source);
|
||||
}
|
||||
|
||||
// TODO: Add safe/unsafe return variable (for variant cases)
|
||||
bool GDScriptAnalyzer::check_type_compatibility(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion, const GDScriptParser::Node *p_source_node) {
|
||||
// These return "true" so it doesn't affect users negatively.
|
||||
|
|
@ -6538,7 +6377,7 @@ void GDScriptAnalyzer::resolve_pending_lambda_bodies() {
|
|||
GDScriptParser::LambdaNode *previous_lambda = current_lambda;
|
||||
bool previous_static_context = static_context;
|
||||
|
||||
List<GDScriptParser::LambdaNode *> lambdas = std::move(pending_body_resolution_lambdas);
|
||||
List<GDScriptParser::LambdaNode *> lambdas = pending_body_resolution_lambdas;
|
||||
pending_body_resolution_lambdas.clear();
|
||||
|
||||
for (GDScriptParser::LambdaNode *lambda : lambdas) {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "gdscript_cache.h"
|
||||
#include "gdscript_parser.h"
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
class GDScriptAnalyzer {
|
||||
|
|
@ -80,7 +81,7 @@ class GDScriptAnalyzer {
|
|||
void resolve_function_signature(GDScriptParser::FunctionNode *p_function, const GDScriptParser::Node *p_source = nullptr, bool p_is_lambda = false);
|
||||
void resolve_function_body(GDScriptParser::FunctionNode *p_function, bool p_is_lambda = false);
|
||||
void resolve_node(GDScriptParser::Node *p_node, bool p_is_root = true);
|
||||
void resolve_suite(GDScriptParser::SuiteNode *p_suite, bool p_is_root = true);
|
||||
void resolve_suite(GDScriptParser::SuiteNode *p_suite);
|
||||
void resolve_assignable(GDScriptParser::AssignableNode *p_assignable, const char *p_kind);
|
||||
void resolve_variable(GDScriptParser::VariableNode *p_variable, bool p_is_local);
|
||||
void resolve_constant(GDScriptParser::ConstantNode *p_constant, bool p_is_local);
|
||||
|
|
@ -115,24 +116,15 @@ class GDScriptAnalyzer {
|
|||
void reduce_type_test(GDScriptParser::TypeTestNode *p_type_test);
|
||||
void reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op);
|
||||
|
||||
// These methods provide a fallback mechanism for constant folding in constant contexts (constant initializers,
|
||||
// annotation arguments) and allow constant folding even when the normal constant folding mechanism does not consider
|
||||
// an expression to be constant (usually due to the presence of `[...]` and `{...}` constructs in it).
|
||||
// These methods assume that the normal expression reduction mechanism has already been performed.
|
||||
Variant make_expression_reduced_value(GDScriptParser::ExpressionNode *p_expression, bool &r_is_reduced);
|
||||
Variant make_array_reduced_value(GDScriptParser::ArrayNode *p_array, bool &r_is_reduced);
|
||||
Variant make_dictionary_reduced_value(GDScriptParser::DictionaryNode *p_dictionary, bool &r_is_reduced);
|
||||
Variant make_subscript_reduced_value(GDScriptParser::SubscriptNode *p_subscript, bool &r_is_reduced);
|
||||
Variant make_call_reduced_value(GDScriptParser::CallNode *p_call, bool &r_is_reduced);
|
||||
Variant make_binary_op_reduced_value(GDScriptParser::BinaryOpNode *p_binary_op, bool &r_is_reduced);
|
||||
Variant make_ternary_op_reduced_value(GDScriptParser::TernaryOpNode *p_ternary_op, bool &r_is_reduced);
|
||||
Variant make_cast_reduced_value(GDScriptParser::CastNode *p_cast, bool &r_is_reduced);
|
||||
Variant make_type_test_reduced_value(GDScriptParser::TypeTestNode *p_type_test, bool &r_is_reduced);
|
||||
Variant make_expression_reduced_value(GDScriptParser::ExpressionNode *p_expression, bool &is_reduced);
|
||||
Variant make_array_reduced_value(GDScriptParser::ArrayNode *p_array, bool &is_reduced);
|
||||
Variant make_dictionary_reduced_value(GDScriptParser::DictionaryNode *p_dictionary, bool &is_reduced);
|
||||
Variant make_subscript_reduced_value(GDScriptParser::SubscriptNode *p_subscript, bool &is_reduced);
|
||||
Variant make_call_reduced_value(GDScriptParser::CallNode *p_call, bool &is_reduced);
|
||||
|
||||
// Helpers.
|
||||
Array make_array_from_element_datatype(const GDScriptParser::DataType &p_element_datatype, const GDScriptParser::Node *p_source_node = nullptr);
|
||||
Dictionary make_dictionary_from_element_datatype(const GDScriptParser::DataType &p_key_element_datatype, const GDScriptParser::DataType &p_value_element_datatype, const GDScriptParser::Node *p_source_node = nullptr);
|
||||
GDScriptParser::DataType type_from_script(const Ref<Script> &p_script, const GDScriptParser::Node *p_source, bool p_is_meta_type);
|
||||
GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);
|
||||
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property, bool p_is_arg = false, bool p_is_readonly = false) const;
|
||||
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
|
||||
|
|
@ -146,7 +138,6 @@ class GDScriptAnalyzer {
|
|||
void update_array_literal_element_type(GDScriptParser::ArrayNode *p_array, const GDScriptParser::DataType &p_element_type);
|
||||
void update_dictionary_literal_element_type(GDScriptParser::DictionaryNode *p_dictionary, const GDScriptParser::DataType &p_key_element_type, const GDScriptParser::DataType &p_value_element_type);
|
||||
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false, const GDScriptParser::Node *p_source_node = nullptr);
|
||||
bool is_type_compatible_strict_collections(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source);
|
||||
void push_error(const String &p_message, const GDScriptParser::Node *p_origin = nullptr);
|
||||
void mark_node_unsafe(const GDScriptParser::Node *p_node);
|
||||
void downgrade_node_type_source(GDScriptParser::Node *p_node);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#include "gdscript_byte_codegen.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/debugger/engine_debugger.h"
|
||||
|
||||
uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool p_is_optional, const GDScriptDataType &p_type) {
|
||||
function->_argument_count++;
|
||||
|
|
@ -189,7 +189,7 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
|
|||
opcodes.write[temporaries[i].bytecode_indices[j]] = stack_index | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
|
||||
}
|
||||
if (temporaries[i].type != Variant::NIL) {
|
||||
function->temporary_slots.push_back(Pair(stack_index, temporaries[i].type));
|
||||
function->temporary_slots[stack_index] = temporaries[i].type;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -200,9 +200,6 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
|
|||
for (const KeyValue<Variant, int> &K : constant_map) {
|
||||
function->constants.write[K.value] = K.key;
|
||||
}
|
||||
for (const KeyValue<StringName, int> &K : local_constants) {
|
||||
function->constant_map.insert(K.key, function->constants[K.value]);
|
||||
}
|
||||
} else {
|
||||
function->_constants_ptr = nullptr;
|
||||
function->_constant_count = 0;
|
||||
|
|
@ -1834,30 +1831,23 @@ void GDScriptByteCodeGenerator::write_newline(int p_line) {
|
|||
}
|
||||
}
|
||||
|
||||
void GDScriptByteCodeGenerator::write_return(const Address &p_return_value, bool p_use_conversion) {
|
||||
if (!p_use_conversion) {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
append(p_return_value);
|
||||
return;
|
||||
}
|
||||
void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
|
||||
if (!function->return_type.has_type() || p_return_value.type.has_type()) {
|
||||
// Either the function is untyped or the return value is also typed.
|
||||
|
||||
switch (function->return_type.kind) {
|
||||
case GDScriptDataType::VARIANT: {
|
||||
ERR_PRINT("Compiler bug: Unresolved return.");
|
||||
|
||||
// Shouldn't get here, but fail-safe to a regular return.
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
append(p_return_value);
|
||||
} break;
|
||||
case GDScriptDataType::BUILTIN: {
|
||||
if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {
|
||||
// If this is a typed function, then we need to check for potential conversions.
|
||||
if (function->return_type.has_type()) {
|
||||
if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {
|
||||
// Typed array.
|
||||
const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);
|
||||
append(p_return_value);
|
||||
append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
|
||||
append(element_type.builtin_type);
|
||||
append(element_type.native_type);
|
||||
} else if (function->return_type.builtin_type == Variant::DICTIONARY && function->return_type.has_container_element_types()) {
|
||||
} else if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::DICTIONARY &&
|
||||
function->return_type.has_container_element_types()) {
|
||||
// Typed dictionary.
|
||||
const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);
|
||||
const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);
|
||||
|
|
@ -1868,29 +1858,72 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value, bool
|
|||
append(key_type.native_type);
|
||||
append(value_type.builtin_type);
|
||||
append(value_type.native_type);
|
||||
} else {
|
||||
} else if (function->return_type.kind == GDScriptDataType::BUILTIN && p_return_value.type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type != p_return_value.type.builtin_type) {
|
||||
// Add conversion.
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);
|
||||
append(p_return_value);
|
||||
append(function->return_type.builtin_type);
|
||||
} else {
|
||||
// Just assign.
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
append(p_return_value);
|
||||
}
|
||||
} break;
|
||||
case GDScriptDataType::NATIVE: {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE);
|
||||
} else {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
append(p_return_value);
|
||||
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
|
||||
Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
|
||||
class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
append(class_idx);
|
||||
} break;
|
||||
case GDScriptDataType::SCRIPT:
|
||||
case GDScriptDataType::GDSCRIPT: {
|
||||
Variant script = function->return_type.script_type;
|
||||
int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
}
|
||||
} else {
|
||||
switch (function->return_type.kind) {
|
||||
case GDScriptDataType::BUILTIN: {
|
||||
if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {
|
||||
const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);
|
||||
append(p_return_value);
|
||||
append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
|
||||
append(element_type.builtin_type);
|
||||
append(element_type.native_type);
|
||||
} else if (function->return_type.builtin_type == Variant::DICTIONARY && function->return_type.has_container_element_types()) {
|
||||
const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);
|
||||
const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);
|
||||
append(p_return_value);
|
||||
append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
|
||||
append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
|
||||
append(key_type.builtin_type);
|
||||
append(key_type.native_type);
|
||||
append(value_type.builtin_type);
|
||||
append(value_type.native_type);
|
||||
} else {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);
|
||||
append(p_return_value);
|
||||
append(function->return_type.builtin_type);
|
||||
}
|
||||
} break;
|
||||
case GDScriptDataType::NATIVE: {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE);
|
||||
append(p_return_value);
|
||||
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
|
||||
Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
|
||||
class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
append(class_idx);
|
||||
} break;
|
||||
case GDScriptDataType::GDSCRIPT:
|
||||
case GDScriptDataType::SCRIPT: {
|
||||
Variant script = function->return_type.script_type;
|
||||
int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT);
|
||||
append(p_return_value);
|
||||
append(script_idx);
|
||||
} break;
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT);
|
||||
append(p_return_value);
|
||||
append(script_idx);
|
||||
} break;
|
||||
default: {
|
||||
ERR_PRINT("Compiler bug: unresolved return.");
|
||||
|
||||
// Shouldn't get here, but fail-safe to a regular return;
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
append(p_return_value);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -552,7 +552,7 @@ public:
|
|||
virtual void write_continue() override;
|
||||
virtual void write_breakpoint() override;
|
||||
virtual void write_newline(int p_line) override;
|
||||
virtual void write_return(const Address &p_return_value, bool p_use_conversion) override;
|
||||
virtual void write_return(const Address &p_return_value) override;
|
||||
virtual void write_assert(const Address &p_test, const Address &p_message) override;
|
||||
|
||||
virtual ~GDScriptByteCodeGenerator();
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
#include "gdscript_parser.h"
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/templates/vector.h"
|
||||
|
||||
GDScriptParserRef::Status GDScriptParserRef::get_status() const {
|
||||
|
|
@ -69,10 +68,6 @@ Error GDScriptParserRef::raise_status(Status p_new_status) {
|
|||
ERR_FAIL_COND_V(clearing, ERR_BUG);
|
||||
ERR_FAIL_COND_V(parser == nullptr && status != EMPTY, ERR_BUG);
|
||||
|
||||
if (p_new_status < status) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
while (result == OK && p_new_status > status) {
|
||||
switch (status) {
|
||||
case EMPTY: {
|
||||
|
|
@ -260,7 +255,7 @@ void GDScriptCache::remove_parser(const String &p_path) {
|
|||
singleton->parser_map.erase(p_path);
|
||||
|
||||
// Have to copy while iterating, because parser_inverse_dependencies is modified.
|
||||
HashSet<String> ideps(singleton->parser_inverse_dependencies[p_path]);
|
||||
HashSet<String> ideps = singleton->parser_inverse_dependencies[p_path];
|
||||
singleton->parser_inverse_dependencies.erase(p_path);
|
||||
for (String idep_path : ideps) {
|
||||
remove_parser(idep_path);
|
||||
|
|
@ -428,7 +423,7 @@ Error GDScriptCache::finish_compiling(const String &p_owner) {
|
|||
singleton->full_gdscript_cache[p_owner] = script;
|
||||
singleton->shallow_gdscript_cache.erase(p_owner);
|
||||
|
||||
HashSet<String> depends(singleton->dependencies[p_owner]);
|
||||
HashSet<String> depends = singleton->dependencies[p_owner];
|
||||
|
||||
Error err = OK;
|
||||
for (const String &E : depends) {
|
||||
|
|
|
|||
|
|
@ -78,9 +78,11 @@ public:
|
|||
~GDScriptParserRef();
|
||||
};
|
||||
|
||||
#ifdef TESTS_ENABLED
|
||||
namespace GDScriptTests {
|
||||
class TestGDScriptCacheAccessor;
|
||||
}
|
||||
#endif // TESTS_ENABLED
|
||||
|
||||
class GDScriptCache {
|
||||
// String key is full path.
|
||||
|
|
@ -95,7 +97,9 @@ class GDScriptCache {
|
|||
friend class GDScript;
|
||||
friend class GDScriptParserRef;
|
||||
friend class GDScriptInstance;
|
||||
#ifdef TESTS_ENABLED
|
||||
friend class GDScriptTests::TestGDScriptCacheAccessor;
|
||||
#endif // TESTS_ENABLED
|
||||
|
||||
static GDScriptCache *singleton;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "gdscript_function.h"
|
||||
#include "gdscript_utility_functions.h"
|
||||
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
|
@ -159,7 +160,7 @@ public:
|
|||
virtual void write_continue() = 0;
|
||||
virtual void write_breakpoint() = 0;
|
||||
virtual void write_newline(int p_line) = 0;
|
||||
virtual void write_return(const Address &p_return_value, bool p_use_conversion) = 0;
|
||||
virtual void write_return(const Address &p_return_value) = 0;
|
||||
virtual void write_assert(const Address &p_test, const Address &p_message) = 0;
|
||||
|
||||
virtual ~GDScriptCodeGenerator() {}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@
|
|||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
#include "scene/scene_string_names.h"
|
||||
|
||||
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
|
||||
if (codegen.function_node && codegen.function_node->is_static) {
|
||||
|
|
@ -419,7 +419,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
|||
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
|
||||
// If it's an autoload singleton, we postpone to load it at runtime.
|
||||
// This is so one autoload doesn't try to load another before it's compiled.
|
||||
HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads(ProjectSettings::get_singleton()->get_autoload_list());
|
||||
HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
|
||||
if (autoloads.has(identifier) && autoloads[identifier].is_singleton) {
|
||||
GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype(), codegen.script));
|
||||
int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
|
||||
|
|
@ -2169,10 +2169,10 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
|
|||
}
|
||||
|
||||
if (return_n->void_return) {
|
||||
// Always return `null`, even if the expression is a call to a `void` function.
|
||||
gen->write_return(codegen.add_constant(Variant()), false);
|
||||
// Always return "null", even if the expression is a call to a void function.
|
||||
gen->write_return(codegen.add_constant(Variant()));
|
||||
} else {
|
||||
gen->write_return(return_value, return_n->use_conversion);
|
||||
gen->write_return(return_value);
|
||||
}
|
||||
if (return_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
|
||||
codegen.generator->pop_temporary();
|
||||
|
|
@ -2796,26 +2796,23 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP
|
|||
return err;
|
||||
}
|
||||
} else if (!base->is_valid()) {
|
||||
String base_qualified_name = base->fully_qualified_name;
|
||||
String base_path = base->path;
|
||||
|
||||
Error err = OK;
|
||||
Ref<GDScript> base_root = GDScriptCache::get_shallow_script(base_path, err, p_script->path);
|
||||
Ref<GDScript> base_root = GDScriptCache::get_shallow_script(base->path, err, p_script->path);
|
||||
if (err) {
|
||||
_set_error(vformat(R"(Could not parse base class "%s" from "%s": %s)", base_qualified_name, base_path, error_names[err]), nullptr);
|
||||
_set_error(vformat(R"(Could not parse base class "%s" from "%s": %s)", base->fully_qualified_name, base->path, error_names[err]), nullptr);
|
||||
return err;
|
||||
}
|
||||
if (base_root.is_valid()) {
|
||||
base = Ref<GDScript>(base_root->find_class(base_qualified_name));
|
||||
base = Ref<GDScript>(base_root->find_class(base->fully_qualified_name));
|
||||
}
|
||||
if (base.is_null()) {
|
||||
_set_error(vformat(R"(Could not find class "%s" in "%s".)", base_qualified_name, base_path), nullptr);
|
||||
_set_error(vformat(R"(Could not find class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr);
|
||||
return ERR_COMPILATION_FAILED;
|
||||
}
|
||||
|
||||
err = _prepare_compilation(base.ptr(), p_class->base_type.class_type, p_keep_state);
|
||||
if (err) {
|
||||
_set_error(vformat(R"(Could not populate class members of base class "%s" in "%s".)", base_qualified_name, base_path), nullptr);
|
||||
_set_error(vformat(R"(Could not populate class members of base class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
|
@ -2863,11 +2860,9 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP
|
|||
}
|
||||
break;
|
||||
}
|
||||
minfo.data_type = _gdtype_from_datatype(variable->get_datatype(), p_script);
|
||||
|
||||
const GDScriptParser::DataType variable_type = variable->get_datatype();
|
||||
minfo.data_type = _gdtype_from_datatype(variable_type, p_script);
|
||||
|
||||
PropertyInfo prop_info = variable_type.to_property_info(name);
|
||||
PropertyInfo prop_info = variable->get_datatype().to_property_info(name);
|
||||
PropertyInfo export_info = variable->export_info;
|
||||
|
||||
if (variable->exported) {
|
||||
|
|
@ -2878,28 +2873,6 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP
|
|||
prop_info.hint = export_info.hint;
|
||||
prop_info.hint_string = export_info.hint_string;
|
||||
prop_info.usage = export_info.usage;
|
||||
} else {
|
||||
// Enum hint doesn't really belong to the data type information, so we don't want to add it to
|
||||
// `GDScriptParser::DataType::to_property_info()`. However, we still want to add this metadata
|
||||
// for unexported properties so they display nicely in the Remote Tree Inspector.
|
||||
if (variable_type.kind == GDScriptParser::DataType::ENUM && !variable_type.is_meta_type) {
|
||||
prop_info.hint = PROPERTY_HINT_ENUM;
|
||||
|
||||
String enum_hint_string;
|
||||
bool first = true;
|
||||
for (const KeyValue<StringName, int64_t> &E : variable_type.enum_values) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
enum_hint_string += ",";
|
||||
}
|
||||
enum_hint_string += E.key.operator String().capitalize().xml_escape();
|
||||
enum_hint_string += ":";
|
||||
enum_hint_string += String::num_int64(E.value).xml_escape();
|
||||
}
|
||||
|
||||
prop_info.hint_string = enum_hint_string;
|
||||
}
|
||||
}
|
||||
prop_info.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
|
||||
minfo.property_info = prop_info;
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ class GDScriptCompiler {
|
|||
}
|
||||
|
||||
void start_block() {
|
||||
HashMap<StringName, GDScriptCodeGenerator::Address> old_locals(locals);
|
||||
HashMap<StringName, GDScriptCodeGenerator::Address> old_locals = locals;
|
||||
locals_stack.push_back(old_locals);
|
||||
generator->start_block();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@
|
|||
#include "gdscript.h"
|
||||
#include "gdscript_function.h"
|
||||
|
||||
#include "core/object/method_bind.h"
|
||||
#include "core/string/string_builder.h"
|
||||
|
||||
static String _get_variant_string(const Variant &p_variant) {
|
||||
|
|
@ -1117,56 +1116,56 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
|
|||
incr += 3;
|
||||
} break;
|
||||
|
||||
#define DISASSEMBLE_ITERATE(m_type) \
|
||||
case OPCODE_ITERATE_##m_type: { \
|
||||
text += "for-loop (typed "; \
|
||||
text += #m_type; \
|
||||
text += ") "; \
|
||||
text += DADDR(3); \
|
||||
text += " in "; \
|
||||
text += DADDR(2); \
|
||||
text += " counter "; \
|
||||
text += DADDR(1); \
|
||||
text += " end "; \
|
||||
#define DISASSEMBLE_ITERATE(m_type) \
|
||||
case OPCODE_ITERATE_##m_type: { \
|
||||
text += "for-loop (typed "; \
|
||||
text += #m_type; \
|
||||
text += ") "; \
|
||||
text += DADDR(3); \
|
||||
text += " in "; \
|
||||
text += DADDR(2); \
|
||||
text += " counter "; \
|
||||
text += DADDR(1); \
|
||||
text += " end "; \
|
||||
text += itos(_code_ptr[ip + 4]); \
|
||||
incr += 5; \
|
||||
incr += 5; \
|
||||
} break
|
||||
|
||||
#define DISASSEMBLE_ITERATE_BEGIN(m_type) \
|
||||
case OPCODE_ITERATE_BEGIN_##m_type: { \
|
||||
text += "for-init (typed "; \
|
||||
text += #m_type; \
|
||||
text += ") "; \
|
||||
text += DADDR(3); \
|
||||
text += " in "; \
|
||||
text += DADDR(2); \
|
||||
text += " counter "; \
|
||||
text += DADDR(1); \
|
||||
text += " end "; \
|
||||
text += itos(_code_ptr[ip + 4]); \
|
||||
incr += 5; \
|
||||
text += "for-init (typed "; \
|
||||
text += #m_type; \
|
||||
text += ") "; \
|
||||
text += DADDR(3); \
|
||||
text += " in "; \
|
||||
text += DADDR(2); \
|
||||
text += " counter "; \
|
||||
text += DADDR(1); \
|
||||
text += " end "; \
|
||||
text += itos(_code_ptr[ip + 4]); \
|
||||
incr += 5; \
|
||||
} break
|
||||
|
||||
#define DISASSEMBLE_ITERATE_TYPES(m_macro) \
|
||||
m_macro(INT); \
|
||||
m_macro(FLOAT); \
|
||||
m_macro(VECTOR2); \
|
||||
m_macro(VECTOR2I); \
|
||||
m_macro(VECTOR3); \
|
||||
m_macro(VECTOR3I); \
|
||||
m_macro(STRING); \
|
||||
m_macro(DICTIONARY); \
|
||||
m_macro(ARRAY); \
|
||||
m_macro(PACKED_BYTE_ARRAY); \
|
||||
m_macro(PACKED_INT32_ARRAY); \
|
||||
m_macro(PACKED_INT64_ARRAY); \
|
||||
m_macro(PACKED_FLOAT32_ARRAY); \
|
||||
m_macro(PACKED_FLOAT64_ARRAY); \
|
||||
m_macro(PACKED_STRING_ARRAY); \
|
||||
m_macro(PACKED_VECTOR2_ARRAY); \
|
||||
m_macro(PACKED_VECTOR3_ARRAY); \
|
||||
m_macro(PACKED_COLOR_ARRAY); \
|
||||
m_macro(PACKED_VECTOR4_ARRAY); \
|
||||
m_macro(INT); \
|
||||
m_macro(FLOAT); \
|
||||
m_macro(VECTOR2); \
|
||||
m_macro(VECTOR2I); \
|
||||
m_macro(VECTOR3); \
|
||||
m_macro(VECTOR3I); \
|
||||
m_macro(STRING); \
|
||||
m_macro(DICTIONARY); \
|
||||
m_macro(ARRAY); \
|
||||
m_macro(PACKED_BYTE_ARRAY); \
|
||||
m_macro(PACKED_INT32_ARRAY); \
|
||||
m_macro(PACKED_INT64_ARRAY); \
|
||||
m_macro(PACKED_FLOAT32_ARRAY); \
|
||||
m_macro(PACKED_FLOAT64_ARRAY); \
|
||||
m_macro(PACKED_STRING_ARRAY); \
|
||||
m_macro(PACKED_VECTOR2_ARRAY); \
|
||||
m_macro(PACKED_VECTOR3_ARRAY); \
|
||||
m_macro(PACKED_COLOR_ARRAY); \
|
||||
m_macro(PACKED_VECTOR4_ARRAY); \
|
||||
m_macro(OBJECT)
|
||||
|
||||
case OPCODE_ITERATE_BEGIN: {
|
||||
|
|
@ -1257,11 +1256,11 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
|
|||
|
||||
#define DISASSEMBLE_TYPE_ADJUST(m_v_type) \
|
||||
case OPCODE_TYPE_ADJUST_##m_v_type: { \
|
||||
text += "type adjust ("; \
|
||||
text += #m_v_type; \
|
||||
text += ") "; \
|
||||
text += DADDR(1); \
|
||||
incr += 2; \
|
||||
text += "type adjust ("; \
|
||||
text += #m_v_type; \
|
||||
text += ") "; \
|
||||
text += DADDR(1); \
|
||||
incr += 2; \
|
||||
} break
|
||||
|
||||
DISASSEMBLE_TYPE_ADJUST(BOOL);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
/**************************************************************************/
|
||||
|
||||
#include "gdscript.h"
|
||||
|
||||
#include "gdscript_analyzer.h"
|
||||
#include "gdscript_parser.h"
|
||||
#include "gdscript_tokenizer.h"
|
||||
|
|
@ -42,9 +43,7 @@
|
|||
#include "core/config/engine.h"
|
||||
#include "core/core_constants.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/math/expression.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/variant/container_type_validate.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
|
@ -170,8 +169,8 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li
|
|||
for (const GDScriptParser::ParserError &pe : parser.get_errors()) {
|
||||
ScriptLanguage::ScriptError e;
|
||||
e.path = p_path;
|
||||
e.line = pe.start_line;
|
||||
e.column = pe.start_column;
|
||||
e.line = pe.line;
|
||||
e.column = pe.column;
|
||||
e.message = pe.message;
|
||||
r_errors->push_back(e);
|
||||
}
|
||||
|
|
@ -181,8 +180,8 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li
|
|||
for (const GDScriptParser::ParserError &pe : depended_parser->get_errors()) {
|
||||
ScriptLanguage::ScriptError e;
|
||||
e.path = E.key;
|
||||
e.line = pe.start_line;
|
||||
e.column = pe.start_column;
|
||||
e.line = pe.line;
|
||||
e.column = pe.column;
|
||||
e.message = pe.message;
|
||||
r_errors->push_back(e);
|
||||
}
|
||||
|
|
@ -247,6 +246,10 @@ int GDScriptLanguage::find_function(const String &p_function, const String &p_co
|
|||
return -1;
|
||||
}
|
||||
|
||||
Script *GDScriptLanguage::create_script() const {
|
||||
return memnew(GDScript);
|
||||
}
|
||||
|
||||
/* DEBUGGER FUNCTIONS */
|
||||
|
||||
thread_local int GDScriptLanguage::_debug_parse_err_line = -1;
|
||||
|
|
@ -342,12 +345,7 @@ void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p
|
|||
f->debug_get_stack_member_state(*cl->line, &locals);
|
||||
for (const Pair<StringName, int> &E : locals) {
|
||||
p_locals->push_back(E.first);
|
||||
|
||||
if (f->constant_map.has(E.first)) {
|
||||
p_values->push_back(f->constant_map[E.first]);
|
||||
} else {
|
||||
p_values->push_back(cl->stack[E.second]);
|
||||
}
|
||||
p_values->push_back(cl->stack[E.second]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -478,7 +476,7 @@ void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const
|
|||
MethodInfo mi;
|
||||
mi.name = "preload";
|
||||
mi.arguments.push_back(PropertyInfo(Variant::STRING, "path"));
|
||||
mi.return_val = PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, Resource::get_class_static());
|
||||
mi.return_val = PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, "Resource");
|
||||
p_functions->push_back(mi);
|
||||
}
|
||||
{
|
||||
|
|
@ -940,7 +938,7 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
|
|||
ScriptLanguage::CodeCompletionOption hint1("attenuation", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
|
||||
hint1.insert_text = hint1.display.quote(p_quote_style);
|
||||
r_result.insert(hint1.display, hint1);
|
||||
ScriptLanguage::CodeCompletionOption hint2("positive_only", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
|
||||
ScriptLanguage::CodeCompletionOption hint2("inout", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
|
||||
hint2.insert_text = hint2.display.quote(p_quote_style);
|
||||
r_result.insert(hint2.display, hint2);
|
||||
}
|
||||
|
|
@ -1125,7 +1123,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
|
|||
}
|
||||
|
||||
// Autoload singletons
|
||||
HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads(ProjectSettings::get_singleton()->get_autoload_list());
|
||||
HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
|
||||
|
||||
for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
|
||||
const ProjectSettings::AutoloadInfo &info = E.value;
|
||||
|
|
@ -3345,7 +3343,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result);
|
||||
}
|
||||
|
||||
MethodInfo mi(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, Resource::get_class_static()), "preload", PropertyInfo(Variant::STRING, "path"));
|
||||
MethodInfo mi(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), "preload", PropertyInfo(Variant::STRING, "path"));
|
||||
r_arghint = _make_arguments_hint(mi, p_argidx);
|
||||
return;
|
||||
} else if (p_call->type != GDScriptParser::Node::CALL) {
|
||||
|
|
@ -3466,7 +3464,6 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
|
||||
switch (completion_context.type) {
|
||||
case GDScriptParser::COMPLETION_NONE:
|
||||
case GDScriptParser::COMPLETION_DECLARATION:
|
||||
break;
|
||||
case GDScriptParser::COMPLETION_ANNOTATION: {
|
||||
List<MethodInfo> annotations;
|
||||
|
|
@ -4414,8 +4411,6 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
|
|||
case GDScriptParser::COMPLETION_METHOD:
|
||||
case GDScriptParser::COMPLETION_ASSIGN:
|
||||
case GDScriptParser::COMPLETION_CALL_ARGUMENTS:
|
||||
case GDScriptParser::COMPLETION_DECLARATION:
|
||||
case GDScriptParser::COMPLETION_INHERIT_TYPE:
|
||||
case GDScriptParser::COMPLETION_IDENTIFIER:
|
||||
case GDScriptParser::COMPLETION_PROPERTY_METHOD:
|
||||
case GDScriptParser::COMPLETION_SUBSCRIPT: {
|
||||
|
|
@ -4608,14 +4603,8 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
|
|||
}
|
||||
} break;
|
||||
case GDScriptParser::COMPLETION_OVERRIDE_METHOD: {
|
||||
// This logic applies to any method declaration (override or not),
|
||||
// but shows parent documentation on virtual method overrides.
|
||||
GDScriptParser::DataType base_type = context.current_class->base_type;
|
||||
if (_lookup_symbol_from_base(base_type, p_symbol, r_result) == OK) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
base_type = context.current_class->get_datatype();
|
||||
if (_lookup_symbol_from_base(base_type, p_symbol, r_result) == OK) {
|
||||
return OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,125 +32,6 @@
|
|||
|
||||
#include "gdscript.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
bool GDScriptDataType::is_type(const Variant &p_variant, bool p_allow_implicit_conversion) const {
|
||||
switch (kind) {
|
||||
case VARIANT: {
|
||||
return true;
|
||||
} break;
|
||||
case BUILTIN: {
|
||||
Variant::Type var_type = p_variant.get_type();
|
||||
bool valid = builtin_type == var_type;
|
||||
if (valid && builtin_type == Variant::ARRAY && has_container_element_type(0)) {
|
||||
Array array = p_variant;
|
||||
if (array.is_typed()) {
|
||||
const GDScriptDataType &elem_type = container_element_types[0];
|
||||
Variant::Type array_builtin_type = (Variant::Type)array.get_typed_builtin();
|
||||
StringName array_native_type = array.get_typed_class_name();
|
||||
Ref<Script> array_script_type_ref = array.get_typed_script();
|
||||
|
||||
if (array_script_type_ref.is_valid()) {
|
||||
valid = (elem_type.kind == SCRIPT || elem_type.kind == GDSCRIPT) && elem_type.script_type == array_script_type_ref.ptr();
|
||||
} else if (array_native_type != StringName()) {
|
||||
valid = elem_type.kind == NATIVE && elem_type.native_type == array_native_type;
|
||||
} else {
|
||||
valid = elem_type.kind == BUILTIN && elem_type.builtin_type == array_builtin_type;
|
||||
}
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
} else if (valid && builtin_type == Variant::DICTIONARY && has_container_element_types()) {
|
||||
Dictionary dictionary = p_variant;
|
||||
if (dictionary.is_typed()) {
|
||||
if (dictionary.is_typed_key()) {
|
||||
GDScriptDataType key = get_container_element_type_or_variant(0);
|
||||
Variant::Type key_builtin_type = (Variant::Type)dictionary.get_typed_key_builtin();
|
||||
StringName key_native_type = dictionary.get_typed_key_class_name();
|
||||
Ref<Script> key_script_type_ref = dictionary.get_typed_key_script();
|
||||
|
||||
if (key_script_type_ref.is_valid()) {
|
||||
valid = (key.kind == SCRIPT || key.kind == GDSCRIPT) && key.script_type == key_script_type_ref.ptr();
|
||||
} else if (key_native_type != StringName()) {
|
||||
valid = key.kind == NATIVE && key.native_type == key_native_type;
|
||||
} else {
|
||||
valid = key.kind == BUILTIN && key.builtin_type == key_builtin_type;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid && dictionary.is_typed_value()) {
|
||||
GDScriptDataType value = get_container_element_type_or_variant(1);
|
||||
Variant::Type value_builtin_type = (Variant::Type)dictionary.get_typed_value_builtin();
|
||||
StringName value_native_type = dictionary.get_typed_value_class_name();
|
||||
Ref<Script> value_script_type_ref = dictionary.get_typed_value_script();
|
||||
|
||||
if (value_script_type_ref.is_valid()) {
|
||||
valid = (value.kind == SCRIPT || value.kind == GDSCRIPT) && value.script_type == value_script_type_ref.ptr();
|
||||
} else if (value_native_type != StringName()) {
|
||||
valid = value.kind == NATIVE && value.native_type == value_native_type;
|
||||
} else {
|
||||
valid = value.kind == BUILTIN && value.builtin_type == value_builtin_type;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
} else if (!valid && p_allow_implicit_conversion) {
|
||||
valid = Variant::can_convert_strict(var_type, builtin_type);
|
||||
}
|
||||
return valid;
|
||||
} break;
|
||||
case NATIVE: {
|
||||
if (p_variant.get_type() == Variant::NIL) {
|
||||
return true;
|
||||
}
|
||||
if (p_variant.get_type() != Variant::OBJECT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool was_freed = false;
|
||||
Object *obj = p_variant.get_validated_object_with_check(was_freed);
|
||||
if (!obj) {
|
||||
return !was_freed;
|
||||
}
|
||||
|
||||
if (!ClassDB::is_parent_class(obj->get_class_name(), native_type)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} break;
|
||||
case SCRIPT:
|
||||
case GDSCRIPT: {
|
||||
if (p_variant.get_type() == Variant::NIL) {
|
||||
return true;
|
||||
}
|
||||
if (p_variant.get_type() != Variant::OBJECT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool was_freed = false;
|
||||
Object *obj = p_variant.get_validated_object_with_check(was_freed);
|
||||
if (!obj) {
|
||||
return !was_freed;
|
||||
}
|
||||
|
||||
Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : nullptr;
|
||||
bool valid = false;
|
||||
while (base.is_valid()) {
|
||||
if (base == script_type) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
base = base->get_base_script();
|
||||
}
|
||||
return valid;
|
||||
} break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
|
||||
Variant GDScriptFunction::get_constant(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, constants.size(), "<errconst>");
|
||||
return constants[p_idx];
|
||||
|
|
@ -325,7 +206,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
|
|||
return Variant();
|
||||
#endif
|
||||
}
|
||||
// Do these now to avoid locking again after the call.
|
||||
// Do these now to avoid locking again after the call
|
||||
scripts_list.remove_from_list();
|
||||
instances_list.remove_from_list();
|
||||
}
|
||||
|
|
@ -334,9 +215,26 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
|
|||
Callable::CallError err;
|
||||
Variant ret = function->call(nullptr, nullptr, 0, err, &state);
|
||||
|
||||
function = nullptr; // Cleaned up.
|
||||
bool completed = true;
|
||||
|
||||
// If the return value is a GDScriptFunctionState reference,
|
||||
// then the function did await again after resuming.
|
||||
if (ret.is_ref_counted()) {
|
||||
GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret);
|
||||
if (gdfs && gdfs->function == function) {
|
||||
completed = false;
|
||||
// Keep the first state alive via reference.
|
||||
gdfs->first_state = first_state.is_valid() ? first_state : Ref<GDScriptFunctionState>(this);
|
||||
}
|
||||
}
|
||||
|
||||
function = nullptr; //cleaned up;
|
||||
state.result = Variant();
|
||||
|
||||
if (completed) {
|
||||
_clear_stack();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -379,6 +277,5 @@ GDScriptFunctionState::~GDScriptFunctionState() {
|
|||
MutexLock lock(GDScriptLanguage::singleton->mutex);
|
||||
scripts_list.remove_from_list();
|
||||
instances_list.remove_from_list();
|
||||
_clear_stack();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,120 @@ public:
|
|||
|
||||
_FORCE_INLINE_ bool has_type() const { return kind != VARIANT; }
|
||||
|
||||
bool is_type(const Variant &p_variant, bool p_allow_implicit_conversion = false) const;
|
||||
bool is_type(const Variant &p_variant, bool p_allow_implicit_conversion = false) const {
|
||||
switch (kind) {
|
||||
case VARIANT: {
|
||||
return true;
|
||||
} break;
|
||||
case BUILTIN: {
|
||||
Variant::Type var_type = p_variant.get_type();
|
||||
bool valid = builtin_type == var_type;
|
||||
if (valid && builtin_type == Variant::ARRAY && has_container_element_type(0)) {
|
||||
Array array = p_variant;
|
||||
if (array.is_typed()) {
|
||||
const GDScriptDataType &elem_type = container_element_types[0];
|
||||
Variant::Type array_builtin_type = (Variant::Type)array.get_typed_builtin();
|
||||
StringName array_native_type = array.get_typed_class_name();
|
||||
Ref<Script> array_script_type_ref = array.get_typed_script();
|
||||
|
||||
if (array_script_type_ref.is_valid()) {
|
||||
valid = (elem_type.kind == SCRIPT || elem_type.kind == GDSCRIPT) && elem_type.script_type == array_script_type_ref.ptr();
|
||||
} else if (array_native_type != StringName()) {
|
||||
valid = elem_type.kind == NATIVE && elem_type.native_type == array_native_type;
|
||||
} else {
|
||||
valid = elem_type.kind == BUILTIN && elem_type.builtin_type == array_builtin_type;
|
||||
}
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
} else if (valid && builtin_type == Variant::DICTIONARY && has_container_element_types()) {
|
||||
Dictionary dictionary = p_variant;
|
||||
if (dictionary.is_typed()) {
|
||||
if (dictionary.is_typed_key()) {
|
||||
GDScriptDataType key = get_container_element_type_or_variant(0);
|
||||
Variant::Type key_builtin_type = (Variant::Type)dictionary.get_typed_key_builtin();
|
||||
StringName key_native_type = dictionary.get_typed_key_class_name();
|
||||
Ref<Script> key_script_type_ref = dictionary.get_typed_key_script();
|
||||
|
||||
if (key_script_type_ref.is_valid()) {
|
||||
valid = (key.kind == SCRIPT || key.kind == GDSCRIPT) && key.script_type == key_script_type_ref.ptr();
|
||||
} else if (key_native_type != StringName()) {
|
||||
valid = key.kind == NATIVE && key.native_type == key_native_type;
|
||||
} else {
|
||||
valid = key.kind == BUILTIN && key.builtin_type == key_builtin_type;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid && dictionary.is_typed_value()) {
|
||||
GDScriptDataType value = get_container_element_type_or_variant(1);
|
||||
Variant::Type value_builtin_type = (Variant::Type)dictionary.get_typed_value_builtin();
|
||||
StringName value_native_type = dictionary.get_typed_value_class_name();
|
||||
Ref<Script> value_script_type_ref = dictionary.get_typed_value_script();
|
||||
|
||||
if (value_script_type_ref.is_valid()) {
|
||||
valid = (value.kind == SCRIPT || value.kind == GDSCRIPT) && value.script_type == value_script_type_ref.ptr();
|
||||
} else if (value_native_type != StringName()) {
|
||||
valid = value.kind == NATIVE && value.native_type == value_native_type;
|
||||
} else {
|
||||
valid = value.kind == BUILTIN && value.builtin_type == value_builtin_type;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
} else if (!valid && p_allow_implicit_conversion) {
|
||||
valid = Variant::can_convert_strict(var_type, builtin_type);
|
||||
}
|
||||
return valid;
|
||||
} break;
|
||||
case NATIVE: {
|
||||
if (p_variant.get_type() == Variant::NIL) {
|
||||
return true;
|
||||
}
|
||||
if (p_variant.get_type() != Variant::OBJECT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool was_freed = false;
|
||||
Object *obj = p_variant.get_validated_object_with_check(was_freed);
|
||||
if (!obj) {
|
||||
return !was_freed;
|
||||
}
|
||||
|
||||
if (!ClassDB::is_parent_class(obj->get_class_name(), native_type)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} break;
|
||||
case SCRIPT:
|
||||
case GDSCRIPT: {
|
||||
if (p_variant.get_type() == Variant::NIL) {
|
||||
return true;
|
||||
}
|
||||
if (p_variant.get_type() != Variant::OBJECT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool was_freed = false;
|
||||
Object *obj = p_variant.get_validated_object_with_check(was_freed);
|
||||
if (!obj) {
|
||||
return !was_freed;
|
||||
}
|
||||
|
||||
Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : nullptr;
|
||||
bool valid = false;
|
||||
while (base.is_valid()) {
|
||||
if (base == script_type) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
base = base->get_base_script();
|
||||
}
|
||||
return valid;
|
||||
} break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool can_contain_object() const {
|
||||
if (kind == BUILTIN) {
|
||||
|
|
@ -360,13 +473,12 @@ private:
|
|||
|
||||
SelfList<GDScriptFunction> function_list{ this };
|
||||
mutable Variant nil;
|
||||
TightLocalVector<Pair<int, Variant::Type>> temporary_slots;
|
||||
HashMap<int, Variant::Type> temporary_slots;
|
||||
List<StackDebug> stack_debug;
|
||||
|
||||
Vector<int> code;
|
||||
Vector<int> default_arguments;
|
||||
Vector<Variant> constants;
|
||||
HashMap<StringName, Variant> constant_map;
|
||||
Vector<StringName> global_names;
|
||||
Vector<Variant::ValidatedOperatorEvaluator> operator_funcs;
|
||||
Vector<Variant::ValidatedSetter> setters;
|
||||
|
|
@ -505,6 +617,7 @@ class GDScriptFunctionState : public RefCounted {
|
|||
GDScriptFunction *function = nullptr;
|
||||
GDScriptFunction::CallState state;
|
||||
Variant _signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
Ref<GDScriptFunctionState> first_state;
|
||||
|
||||
SelfList<GDScriptFunctionState> scripts_list;
|
||||
SelfList<GDScriptFunctionState> instances_list;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
#include "core/config/project_settings.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/math/math_defs.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "scene/main/multiplayer_api.h"
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
|
@ -236,22 +235,12 @@ void GDScriptParser::push_error(const String &p_message, const Node *p_origin) {
|
|||
// TODO: Improve error reporting by pointing at source code.
|
||||
// TODO: Errors might point at more than one place at once (e.g. show previous declaration).
|
||||
panic_mode = true;
|
||||
ParserError err;
|
||||
err.message = p_message;
|
||||
|
||||
// TODO: Improve positional information.
|
||||
if (p_origin == nullptr) {
|
||||
err.start_line = previous.start_line;
|
||||
err.start_column = previous.start_column;
|
||||
err.end_line = previous.end_line;
|
||||
err.end_column = previous.end_column;
|
||||
errors.push_back({ p_message, previous.start_line, previous.start_column });
|
||||
} else {
|
||||
err.start_line = p_origin->start_line;
|
||||
err.start_column = p_origin->start_column;
|
||||
err.end_line = p_origin->end_line;
|
||||
err.end_column = p_origin->end_column;
|
||||
errors.push_back({ p_message, p_origin->start_line, p_origin->start_column });
|
||||
}
|
||||
|
||||
errors.push_back(err);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
|
@ -290,9 +279,7 @@ void GDScriptParser::apply_pending_warnings() {
|
|||
warning.code = pw.code;
|
||||
warning.symbols = pw.symbols;
|
||||
warning.start_line = pw.source->start_line;
|
||||
warning.start_column = pw.source->start_column;
|
||||
warning.end_line = pw.source->end_line;
|
||||
warning.end_column = pw.source->end_column;
|
||||
|
||||
if (pw.treated_as_error) {
|
||||
push_error(warning.get_message() + String(" (Warning treated as error.)"), pw.source);
|
||||
|
|
@ -704,12 +691,12 @@ void GDScriptParser::parse_program() {
|
|||
current_class = head;
|
||||
bool can_have_class_or_extends = true;
|
||||
|
||||
#define PUSH_PENDING_ANNOTATIONS_TO_HEAD \
|
||||
if (!annotation_stack.is_empty()) { \
|
||||
#define PUSH_PENDING_ANNOTATIONS_TO_HEAD \
|
||||
if (!annotation_stack.is_empty()) { \
|
||||
for (AnnotationNode *annot : annotation_stack) { \
|
||||
head->annotations.push_back(annot); \
|
||||
} \
|
||||
annotation_stack.clear(); \
|
||||
head->annotations.push_back(annot); \
|
||||
} \
|
||||
annotation_stack.clear(); \
|
||||
}
|
||||
|
||||
while (!check(GDScriptTokenizer::Token::TK_EOF)) {
|
||||
|
|
@ -938,8 +925,6 @@ bool GDScriptParser::has_class(const GDScriptParser::ClassNode *p_class) const {
|
|||
GDScriptParser::ClassNode *GDScriptParser::parse_class(bool p_is_static) {
|
||||
ClassNode *n_class = alloc_node<ClassNode>();
|
||||
|
||||
make_completion_context(COMPLETION_DECLARATION, n_class);
|
||||
|
||||
ClassNode *previous_class = current_class;
|
||||
current_class = n_class;
|
||||
n_class->outer = previous_class;
|
||||
|
|
@ -996,12 +981,6 @@ void GDScriptParser::parse_class_name() {
|
|||
current_class->fqcn = String(current_class->identifier->name);
|
||||
}
|
||||
|
||||
if (script_path.begins_with("res://") && script_path.contains("::")) {
|
||||
push_error(R"("class_name" isn't allowed in built-in scripts.)");
|
||||
}
|
||||
|
||||
make_completion_context(COMPLETION_DECLARATION, current_class);
|
||||
|
||||
if (match(GDScriptTokenizer::Token::EXTENDS)) {
|
||||
// Allow extends on the same line.
|
||||
parse_extends();
|
||||
|
|
@ -1235,8 +1214,6 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_is_static) {
|
|||
GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_is_static, bool p_allow_property) {
|
||||
VariableNode *variable = alloc_node<VariableNode>();
|
||||
|
||||
make_completion_context(COMPLETION_DECLARATION, variable);
|
||||
|
||||
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected variable name after "var".)")) {
|
||||
complete_extents(variable);
|
||||
return nullptr;
|
||||
|
|
@ -1473,8 +1450,6 @@ void GDScriptParser::parse_property_getter(VariableNode *p_variable) {
|
|||
GDScriptParser::ConstantNode *GDScriptParser::parse_constant(bool p_is_static) {
|
||||
ConstantNode *constant = alloc_node<ConstantNode>();
|
||||
|
||||
make_completion_context(COMPLETION_DECLARATION, constant);
|
||||
|
||||
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected constant name after "const".)")) {
|
||||
complete_extents(constant);
|
||||
return nullptr;
|
||||
|
|
@ -1543,8 +1518,6 @@ GDScriptParser::ParameterNode *GDScriptParser::parse_parameter() {
|
|||
GDScriptParser::SignalNode *GDScriptParser::parse_signal(bool p_is_static) {
|
||||
SignalNode *signal = alloc_node<SignalNode>();
|
||||
|
||||
make_completion_context(COMPLETION_DECLARATION, signal);
|
||||
|
||||
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected signal name after "signal".)")) {
|
||||
complete_extents(signal);
|
||||
return nullptr;
|
||||
|
|
@ -1591,8 +1564,6 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum(bool p_is_static) {
|
|||
EnumNode *enum_node = alloc_node<EnumNode>();
|
||||
bool named = false;
|
||||
|
||||
make_completion_context(COMPLETION_DECLARATION, enum_node);
|
||||
|
||||
if (match(GDScriptTokenizer::Token::IDENTIFIER)) {
|
||||
enum_node->identifier = parse_identifier();
|
||||
named = true;
|
||||
|
|
@ -3483,9 +3454,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
|
|||
if (!check(GDScriptTokenizer::Token::PERIOD)) {
|
||||
make_completion_context(COMPLETION_SUPER, call);
|
||||
}
|
||||
if (check(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) {
|
||||
push_multiline(true);
|
||||
advance();
|
||||
push_multiline(true);
|
||||
if (match(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) {
|
||||
// Implicit call to the parent method of the same name.
|
||||
if (current_function == nullptr) {
|
||||
push_error(R"(Cannot use implicit "super" call outside of a function.)");
|
||||
|
|
@ -3502,18 +3472,15 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
|
|||
consume(GDScriptTokenizer::Token::PERIOD, R"(Expected "." or "(" after "super".)");
|
||||
make_completion_context(COMPLETION_SUPER_METHOD, call);
|
||||
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after ".".)")) {
|
||||
pop_multiline();
|
||||
complete_extents(call);
|
||||
return nullptr;
|
||||
}
|
||||
IdentifierNode *identifier = parse_identifier();
|
||||
call->callee = identifier;
|
||||
call->function_name = identifier->name;
|
||||
|
||||
if (check(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) {
|
||||
push_multiline(true);
|
||||
advance();
|
||||
} else {
|
||||
push_error(R"(Expected "(" after function name.)");
|
||||
if (!consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected "(" after function name.)")) {
|
||||
pop_multiline();
|
||||
complete_extents(call);
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -3935,24 +3902,20 @@ enum DocLineState {
|
|||
DOC_LINE_IN_KBD,
|
||||
};
|
||||
|
||||
static void _process_doc_line(const String &p_line, String &r_text, const String &p_space_prefix, DocLineState &r_state) {
|
||||
static String _process_doc_line(const String &p_line, const String &p_text, const String &p_space_prefix, DocLineState &r_state) {
|
||||
String line = p_line;
|
||||
if (r_state == DOC_LINE_NORMAL) {
|
||||
line = line.lstrip(" \t");
|
||||
line = line.strip_edges(true, false);
|
||||
} else {
|
||||
line = line.trim_prefix(p_space_prefix);
|
||||
}
|
||||
|
||||
String line_join;
|
||||
if (!r_text.is_empty()) {
|
||||
if (!p_text.is_empty()) {
|
||||
if (r_state == DOC_LINE_NORMAL) {
|
||||
if (r_text.ends_with("[/codeblock]")) {
|
||||
if (p_text.ends_with("[/codeblock]")) {
|
||||
line_join = "\n";
|
||||
} else if (r_text.ends_with("[br]")) {
|
||||
// We want to replace `[br][br]` with `\n` (paragraph), so we move the trailing `[br]` here.
|
||||
r_text = r_text.left(-4); // `-len("[br]")`.
|
||||
line = "[br]" + line;
|
||||
} else if (!r_text.ends_with("\n")) {
|
||||
} else if (!p_text.ends_with("[br]")) {
|
||||
line_join = " ";
|
||||
}
|
||||
} else {
|
||||
|
|
@ -3982,14 +3945,7 @@ static void _process_doc_line(const String &p_line, String &r_text, const String
|
|||
from = rb_pos + 1;
|
||||
|
||||
String tag = line.substr(lb_pos + 1, rb_pos - lb_pos - 1);
|
||||
if (tag == "br") {
|
||||
if (line.substr(from, 4) == "[br]") { // `len("[br]")`.
|
||||
// Replace `[br][br]` with `\n` (paragraph).
|
||||
result += line.substr(buffer_start, lb_pos - buffer_start) + '\n';
|
||||
from += 4; // `len("[br]")`.
|
||||
buffer_start = from;
|
||||
}
|
||||
} else if (tag == "code" || tag.begins_with("code ")) {
|
||||
if (tag == "code" || tag.begins_with("code ")) {
|
||||
r_state = DOC_LINE_IN_CODE;
|
||||
} else if (tag == "codeblock" || tag.begins_with("codeblock ")) {
|
||||
if (lb_pos == 0) {
|
||||
|
|
@ -4057,10 +4013,10 @@ static void _process_doc_line(const String &p_line, String &r_text, const String
|
|||
|
||||
result += line.substr(buffer_start);
|
||||
if (r_state == DOC_LINE_NORMAL) {
|
||||
result = result.rstrip(" \t");
|
||||
result = result.strip_edges(false, true);
|
||||
}
|
||||
|
||||
r_text += line_join + result;
|
||||
return line_join + result;
|
||||
}
|
||||
|
||||
bool GDScriptParser::has_comment(int p_line, bool p_must_be_doc) {
|
||||
|
|
@ -4123,7 +4079,7 @@ GDScriptParser::MemberDocData GDScriptParser::parse_doc_comment(int p_line, bool
|
|||
}
|
||||
}
|
||||
|
||||
_process_doc_line(doc_line, result.description, space_prefix, state);
|
||||
result.description += _process_doc_line(doc_line, result.description, space_prefix, state);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -4233,9 +4189,9 @@ GDScriptParser::ClassDocData GDScriptParser::parse_class_doc_comment(int p_line,
|
|||
}
|
||||
|
||||
if (is_in_brief) {
|
||||
_process_doc_line(doc_line, result.brief, space_prefix, state);
|
||||
result.brief += _process_doc_line(doc_line, result.brief, space_prefix, state);
|
||||
} else {
|
||||
_process_doc_line(doc_line, result.description, space_prefix, state);
|
||||
result.description += _process_doc_line(doc_line, result.description, space_prefix, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4832,10 +4788,10 @@ bool GDScriptParser::export_annotations(AnnotationNode *p_annotation, Node *p_ta
|
|||
String enum_hint_string;
|
||||
bool first = true;
|
||||
for (const KeyValue<StringName, int64_t> &E : export_type.enum_values) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
if (!first) {
|
||||
enum_hint_string += ",";
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
enum_hint_string += E.key.operator String().capitalize().xml_escape();
|
||||
enum_hint_string += ":";
|
||||
|
|
@ -4909,10 +4865,10 @@ bool GDScriptParser::export_annotations(AnnotationNode *p_annotation, Node *p_ta
|
|||
String enum_hint_string;
|
||||
bool first = true;
|
||||
for (const KeyValue<StringName, int64_t> &E : export_type.enum_values) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
if (!first) {
|
||||
enum_hint_string += ",";
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
enum_hint_string += E.key.operator String().capitalize().xml_escape();
|
||||
enum_hint_string += ":";
|
||||
|
|
@ -5132,14 +5088,14 @@ bool GDScriptParser::warning_ignore_annotation(AnnotationNode *p_annotation, Nod
|
|||
int end_line = p_target->end_line;
|
||||
|
||||
switch (p_target->type) {
|
||||
#define SIMPLE_CASE(m_type, m_class, m_property) \
|
||||
case m_type: { \
|
||||
#define SIMPLE_CASE(m_type, m_class, m_property) \
|
||||
case m_type: { \
|
||||
m_class *node = static_cast<m_class *>(p_target); \
|
||||
if (node->m_property == nullptr) { \
|
||||
end_line = node->start_line; \
|
||||
} else { \
|
||||
end_line = node->m_property->end_line; \
|
||||
} \
|
||||
if (node->m_property == nullptr) { \
|
||||
end_line = node->start_line; \
|
||||
} else { \
|
||||
end_line = node->m_property->end_line; \
|
||||
} \
|
||||
} break;
|
||||
|
||||
// Can contain properties (set/get).
|
||||
|
|
|
|||
|
|
@ -269,10 +269,7 @@ public:
|
|||
// };
|
||||
// Type type = NO_ERROR;
|
||||
String message;
|
||||
int start_line = 0;
|
||||
int start_column = 0;
|
||||
int end_line = 0;
|
||||
int end_column = 0;
|
||||
int line = 0, column = 0;
|
||||
};
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
|
@ -340,10 +337,8 @@ public:
|
|||
};
|
||||
|
||||
Type type = NONE;
|
||||
int start_line = 0;
|
||||
int start_column = 0;
|
||||
int end_line = 0;
|
||||
int end_column = 0;
|
||||
int start_line = 0, end_line = 0;
|
||||
int start_column = 0, end_column = 0;
|
||||
Node *next = nullptr;
|
||||
List<AnnotationNode *> annotations;
|
||||
|
||||
|
|
@ -1047,7 +1042,6 @@ public:
|
|||
struct ReturnNode : public Node {
|
||||
ExpressionNode *return_value = nullptr;
|
||||
bool void_return = false;
|
||||
bool use_conversion = false;
|
||||
|
||||
ReturnNode() {
|
||||
type = RETURN;
|
||||
|
|
@ -1114,10 +1108,8 @@ public:
|
|||
StringName name;
|
||||
FunctionNode *source_function = nullptr;
|
||||
|
||||
int start_line = 0;
|
||||
int start_column = 0;
|
||||
int end_line = 0;
|
||||
int end_column = 0;
|
||||
int start_line = 0, end_line = 0;
|
||||
int start_column = 0, end_column = 0;
|
||||
|
||||
DataType get_datatype() const;
|
||||
String get_name() const;
|
||||
|
|
@ -1298,7 +1290,7 @@ public:
|
|||
COMPLETION_ATTRIBUTE_METHOD, // After id.| to look for methods.
|
||||
COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD, // Constants inside a built-in type (e.g. Color.BLUE) or static methods (e.g. Color.html).
|
||||
COMPLETION_CALL_ARGUMENTS, // Complete with nodes, input actions, enum values (or usual expressions).
|
||||
COMPLETION_DECLARATION, // Potential declaration (var, const, class, etc.).
|
||||
// TODO: COMPLETION_DECLARATION, // Potential declaration (var, const, func).
|
||||
COMPLETION_GET_NODE, // Get node with $ notation.
|
||||
COMPLETION_IDENTIFIER, // List available identifiers in scope.
|
||||
COMPLETION_INHERIT_TYPE, // Type after extends. Exclude non-viable types (built-ins, enums, void). Includes subtypes using the argument index.
|
||||
|
|
|
|||
|
|
@ -1,182 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdscript_resource_format.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "gdscript_resource_format.h"
|
||||
|
||||
#include "gdscript_cache.h"
|
||||
#include "gdscript_parser.h"
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
Error err;
|
||||
bool ignoring = p_cache_mode == CACHE_MODE_IGNORE || p_cache_mode == CACHE_MODE_IGNORE_DEEP;
|
||||
Ref<GDScript> scr = GDScriptCache::get_full_script(p_original_path, err, "", ignoring);
|
||||
|
||||
if (err && scr.is_valid()) {
|
||||
// If !scr.is_valid(), the error was likely from scr->load_source_code(), which already generates an error.
|
||||
ERR_PRINT_ED(vformat(R"(Failed to load script "%s" with error "%s".)", p_original_path, error_names[err]));
|
||||
}
|
||||
|
||||
if (r_error) {
|
||||
// Don't fail loading because of parsing error.
|
||||
*r_error = scr.is_valid() ? OK : err;
|
||||
}
|
||||
|
||||
return scr;
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
p_extensions->push_back("gd");
|
||||
p_extensions->push_back("gdc");
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
|
||||
return (p_type == "Script" || p_type == "GDScript");
|
||||
}
|
||||
|
||||
String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
|
||||
String el = p_path.get_extension().to_lower();
|
||||
if (el == "gd" || el == "gdc") {
|
||||
return "GDScript";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
|
||||
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ);
|
||||
ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'.");
|
||||
|
||||
String source = file->get_as_utf8_string();
|
||||
if (source.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GDScriptParser parser;
|
||||
if (OK != parser.parse(source, p_path, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const String &E : parser.get_dependencies()) {
|
||||
p_dependencies->push_back(E);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderGDScript::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
|
||||
Ref<GDScript> scr = ResourceLoader::load(p_path);
|
||||
if (scr.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const String source = scr->get_source_code();
|
||||
GDScriptTokenizerText tokenizer;
|
||||
tokenizer.set_source_code(source);
|
||||
GDScriptTokenizer::Token current = tokenizer.scan();
|
||||
while (current.type != GDScriptTokenizer::Token::TK_EOF) {
|
||||
if (!current.is_identifier()) {
|
||||
current = tokenizer.scan();
|
||||
continue;
|
||||
}
|
||||
|
||||
int insert_idx = 0;
|
||||
for (int i = 0; i < current.start_line - 1; i++) {
|
||||
insert_idx = source.find("\n", insert_idx) + 1;
|
||||
}
|
||||
// Insert the "cursor" character, needed for the lookup to work.
|
||||
const String source_with_cursor = source.insert(insert_idx + current.start_column, String::chr(0xFFFF));
|
||||
|
||||
ScriptLanguage::LookupResult result;
|
||||
if (scr->get_language()->lookup_code(source_with_cursor, current.get_identifier(), p_path, nullptr, result) == OK) {
|
||||
if (!result.class_name.is_empty() && ClassDB::class_exists(result.class_name)) {
|
||||
r_classes->insert(result.class_name);
|
||||
}
|
||||
|
||||
if (result.type == ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY) {
|
||||
PropertyInfo prop;
|
||||
if (ClassDB::get_property_info(result.class_name, result.class_member, &prop)) {
|
||||
if (!prop.class_name.is_empty() && ClassDB::class_exists(prop.class_name)) {
|
||||
r_classes->insert(prop.class_name);
|
||||
}
|
||||
if (!prop.hint_string.is_empty() && ClassDB::class_exists(prop.hint_string)) {
|
||||
r_classes->insert(prop.hint_string);
|
||||
}
|
||||
}
|
||||
} else if (result.type == ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD) {
|
||||
MethodInfo met;
|
||||
if (ClassDB::get_method_info(result.class_name, result.class_member, &met)) {
|
||||
if (!met.return_val.class_name.is_empty() && ClassDB::class_exists(met.return_val.class_name)) {
|
||||
r_classes->insert(met.return_val.class_name);
|
||||
}
|
||||
if (!met.return_val.hint_string.is_empty() && ClassDB::class_exists(met.return_val.hint_string)) {
|
||||
r_classes->insert(met.return_val.hint_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current = tokenizer.scan();
|
||||
}
|
||||
}
|
||||
|
||||
Error ResourceFormatSaverGDScript::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
|
||||
Ref<GDScript> sqscr = p_resource;
|
||||
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
|
||||
|
||||
String source = sqscr->get_source_code();
|
||||
|
||||
{
|
||||
Error err;
|
||||
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
|
||||
|
||||
file->store_string(source);
|
||||
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
|
||||
GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, true);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
|
||||
if (Object::cast_to<GDScript>(*p_resource)) {
|
||||
p_extensions->push_back("gd");
|
||||
}
|
||||
}
|
||||
|
||||
bool ResourceFormatSaverGDScript::recognize(const Ref<Resource> &p_resource) const {
|
||||
return Object::cast_to<GDScript>(*p_resource) != nullptr;
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* gdscript_resource_format.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
|
||||
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
|
||||
GDSOFTCLASS(ResourceFormatLoaderGDScript, ResourceFormatLoader);
|
||||
|
||||
public:
|
||||
virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
virtual bool handles_type(const String &p_type) const override;
|
||||
virtual String get_resource_type(const String &p_path) const override;
|
||||
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override;
|
||||
virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override;
|
||||
};
|
||||
|
||||
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
|
||||
GDSOFTCLASS(ResourceFormatSaverGDScript, ResourceFormatSaver);
|
||||
|
||||
public:
|
||||
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
|
||||
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
|
||||
virtual bool recognize(const Ref<Resource> &p_resource) const override;
|
||||
};
|
||||
|
|
@ -372,6 +372,7 @@ GDScriptTokenizer::Token GDScriptTokenizerText::make_token(Token::Type p_type) {
|
|||
if (start_line == line) {
|
||||
// Single line token.
|
||||
if (cursor_line == start_line && cursor_column >= start_column && cursor_column <= last_column) {
|
||||
token.cursor_position = cursor_column - start_column;
|
||||
if (cursor_column == start_column) {
|
||||
token.cursor_place = CURSOR_BEGINNING;
|
||||
} else if (cursor_column < column) {
|
||||
|
|
@ -384,6 +385,7 @@ GDScriptTokenizer::Token GDScriptTokenizerText::make_token(Token::Type p_type) {
|
|||
// Multi line token.
|
||||
if (cursor_line == start_line && cursor_column >= start_column) {
|
||||
// Is in first line.
|
||||
token.cursor_position = cursor_column - start_column;
|
||||
if (cursor_column == start_column) {
|
||||
token.cursor_place = CURSOR_BEGINNING;
|
||||
} else {
|
||||
|
|
@ -391,6 +393,7 @@ GDScriptTokenizer::Token GDScriptTokenizerText::make_token(Token::Type p_type) {
|
|||
}
|
||||
} else if (cursor_line == line && cursor_column <= last_column) {
|
||||
// Is in last line.
|
||||
token.cursor_position = cursor_column - start_column;
|
||||
if (cursor_column < column) {
|
||||
token.cursor_place = CURSOR_MIDDLE;
|
||||
} else {
|
||||
|
|
@ -398,7 +401,7 @@ GDScriptTokenizer::Token GDScriptTokenizerText::make_token(Token::Type p_type) {
|
|||
}
|
||||
} else if (cursor_line > start_line && cursor_line < line) {
|
||||
// Is in middle line.
|
||||
token.cursor_place = CURSOR_MIDDLE;
|
||||
token.cursor_position = CURSOR_MIDDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -483,66 +486,66 @@ GDScriptTokenizer::Token GDScriptTokenizerText::annotation() {
|
|||
return annotation;
|
||||
}
|
||||
|
||||
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
|
||||
KEYWORD_GROUP('a') \
|
||||
KEYWORD("as", Token::AS) \
|
||||
KEYWORD("and", Token::AND) \
|
||||
KEYWORD("assert", Token::ASSERT) \
|
||||
KEYWORD("await", Token::AWAIT) \
|
||||
KEYWORD_GROUP('b') \
|
||||
KEYWORD("break", Token::BREAK) \
|
||||
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
|
||||
KEYWORD_GROUP('a') \
|
||||
KEYWORD("as", Token::AS) \
|
||||
KEYWORD("and", Token::AND) \
|
||||
KEYWORD("assert", Token::ASSERT) \
|
||||
KEYWORD("await", Token::AWAIT) \
|
||||
KEYWORD_GROUP('b') \
|
||||
KEYWORD("break", Token::BREAK) \
|
||||
KEYWORD("breakpoint", Token::BREAKPOINT) \
|
||||
KEYWORD_GROUP('c') \
|
||||
KEYWORD("class", Token::CLASS) \
|
||||
KEYWORD_GROUP('c') \
|
||||
KEYWORD("class", Token::CLASS) \
|
||||
KEYWORD("class_name", Token::CLASS_NAME) \
|
||||
KEYWORD("const", Token::TK_CONST) \
|
||||
KEYWORD("continue", Token::CONTINUE) \
|
||||
KEYWORD_GROUP('e') \
|
||||
KEYWORD("elif", Token::ELIF) \
|
||||
KEYWORD("else", Token::ELSE) \
|
||||
KEYWORD("enum", Token::ENUM) \
|
||||
KEYWORD("extends", Token::EXTENDS) \
|
||||
KEYWORD_GROUP('f') \
|
||||
KEYWORD("for", Token::FOR) \
|
||||
KEYWORD("func", Token::FUNC) \
|
||||
KEYWORD_GROUP('i') \
|
||||
KEYWORD("if", Token::IF) \
|
||||
KEYWORD("in", Token::TK_IN) \
|
||||
KEYWORD("is", Token::IS) \
|
||||
KEYWORD_GROUP('m') \
|
||||
KEYWORD("match", Token::MATCH) \
|
||||
KEYWORD_GROUP('n') \
|
||||
KEYWORD("namespace", Token::NAMESPACE) \
|
||||
KEYWORD("not", Token::NOT) \
|
||||
KEYWORD_GROUP('o') \
|
||||
KEYWORD("or", Token::OR) \
|
||||
KEYWORD_GROUP('p') \
|
||||
KEYWORD("pass", Token::PASS) \
|
||||
KEYWORD("preload", Token::PRELOAD) \
|
||||
KEYWORD_GROUP('r') \
|
||||
KEYWORD("return", Token::RETURN) \
|
||||
KEYWORD_GROUP('s') \
|
||||
KEYWORD("self", Token::SELF) \
|
||||
KEYWORD("signal", Token::SIGNAL) \
|
||||
KEYWORD("static", Token::STATIC) \
|
||||
KEYWORD("super", Token::SUPER) \
|
||||
KEYWORD_GROUP('t') \
|
||||
KEYWORD("trait", Token::TRAIT) \
|
||||
KEYWORD_GROUP('v') \
|
||||
KEYWORD("var", Token::VAR) \
|
||||
KEYWORD("void", Token::TK_VOID) \
|
||||
KEYWORD_GROUP('w') \
|
||||
KEYWORD("while", Token::WHILE) \
|
||||
KEYWORD("when", Token::WHEN) \
|
||||
KEYWORD_GROUP('y') \
|
||||
KEYWORD("yield", Token::YIELD) \
|
||||
KEYWORD_GROUP('I') \
|
||||
KEYWORD("INF", Token::CONST_INF) \
|
||||
KEYWORD_GROUP('N') \
|
||||
KEYWORD("NAN", Token::CONST_NAN) \
|
||||
KEYWORD_GROUP('P') \
|
||||
KEYWORD("PI", Token::CONST_PI) \
|
||||
KEYWORD_GROUP('T') \
|
||||
KEYWORD("const", Token::TK_CONST) \
|
||||
KEYWORD("continue", Token::CONTINUE) \
|
||||
KEYWORD_GROUP('e') \
|
||||
KEYWORD("elif", Token::ELIF) \
|
||||
KEYWORD("else", Token::ELSE) \
|
||||
KEYWORD("enum", Token::ENUM) \
|
||||
KEYWORD("extends", Token::EXTENDS) \
|
||||
KEYWORD_GROUP('f') \
|
||||
KEYWORD("for", Token::FOR) \
|
||||
KEYWORD("func", Token::FUNC) \
|
||||
KEYWORD_GROUP('i') \
|
||||
KEYWORD("if", Token::IF) \
|
||||
KEYWORD("in", Token::TK_IN) \
|
||||
KEYWORD("is", Token::IS) \
|
||||
KEYWORD_GROUP('m') \
|
||||
KEYWORD("match", Token::MATCH) \
|
||||
KEYWORD_GROUP('n') \
|
||||
KEYWORD("namespace", Token::NAMESPACE) \
|
||||
KEYWORD("not", Token::NOT) \
|
||||
KEYWORD_GROUP('o') \
|
||||
KEYWORD("or", Token::OR) \
|
||||
KEYWORD_GROUP('p') \
|
||||
KEYWORD("pass", Token::PASS) \
|
||||
KEYWORD("preload", Token::PRELOAD) \
|
||||
KEYWORD_GROUP('r') \
|
||||
KEYWORD("return", Token::RETURN) \
|
||||
KEYWORD_GROUP('s') \
|
||||
KEYWORD("self", Token::SELF) \
|
||||
KEYWORD("signal", Token::SIGNAL) \
|
||||
KEYWORD("static", Token::STATIC) \
|
||||
KEYWORD("super", Token::SUPER) \
|
||||
KEYWORD_GROUP('t') \
|
||||
KEYWORD("trait", Token::TRAIT) \
|
||||
KEYWORD_GROUP('v') \
|
||||
KEYWORD("var", Token::VAR) \
|
||||
KEYWORD("void", Token::TK_VOID) \
|
||||
KEYWORD_GROUP('w') \
|
||||
KEYWORD("while", Token::WHILE) \
|
||||
KEYWORD("when", Token::WHEN) \
|
||||
KEYWORD_GROUP('y') \
|
||||
KEYWORD("yield", Token::YIELD) \
|
||||
KEYWORD_GROUP('I') \
|
||||
KEYWORD("INF", Token::CONST_INF) \
|
||||
KEYWORD_GROUP('N') \
|
||||
KEYWORD("NAN", Token::CONST_NAN) \
|
||||
KEYWORD_GROUP('P') \
|
||||
KEYWORD("PI", Token::CONST_PI) \
|
||||
KEYWORD_GROUP('T') \
|
||||
KEYWORD("TAU", Token::CONST_TAU)
|
||||
|
||||
#define MIN_KEYWORD_LENGTH 2
|
||||
|
|
@ -604,18 +607,18 @@ GDScriptTokenizer::Token GDScriptTokenizerText::potential_identifier() {
|
|||
|
||||
// Define some helper macros for the switch case.
|
||||
#define KEYWORD_GROUP_CASE(char) \
|
||||
break; \
|
||||
break; \
|
||||
case char:
|
||||
#define KEYWORD(keyword, token_type) \
|
||||
{ \
|
||||
const int keyword_length = sizeof(keyword) - 1; \
|
||||
static_assert(keyword_length <= MAX_KEYWORD_LENGTH, "There's a keyword longer than the defined maximum length"); \
|
||||
#define KEYWORD(keyword, token_type) \
|
||||
{ \
|
||||
const int keyword_length = sizeof(keyword) - 1; \
|
||||
static_assert(keyword_length <= MAX_KEYWORD_LENGTH, "There's a keyword longer than the defined maximum length"); \
|
||||
static_assert(keyword_length >= MIN_KEYWORD_LENGTH, "There's a keyword shorter than the defined minimum length"); \
|
||||
if (keyword_length == len && name == keyword) { \
|
||||
Token kw = make_token(token_type); \
|
||||
kw.literal = name; \
|
||||
return kw; \
|
||||
} \
|
||||
if (keyword_length == len && name == keyword) { \
|
||||
Token kw = make_token(token_type); \
|
||||
kw.literal = name; \
|
||||
return kw; \
|
||||
} \
|
||||
}
|
||||
|
||||
// Find if it's a keyword.
|
||||
|
|
|
|||
|
|
@ -165,10 +165,8 @@ public:
|
|||
|
||||
Type type = EMPTY;
|
||||
Variant literal;
|
||||
int start_line = 0;
|
||||
int start_column = 0;
|
||||
int end_line = 0;
|
||||
int end_column = 0;
|
||||
int start_line = 0, end_line = 0, start_column = 0, end_column = 0;
|
||||
int cursor_position = -1;
|
||||
CursorPlace cursor_place = CURSOR_NONE;
|
||||
String source;
|
||||
|
||||
|
|
@ -227,16 +225,13 @@ class GDScriptTokenizerText : public GDScriptTokenizer {
|
|||
String source;
|
||||
const char32_t *_source = nullptr;
|
||||
const char32_t *_current = nullptr;
|
||||
int line = 0;
|
||||
int column = 0;
|
||||
int cursor_line = -1;
|
||||
int cursor_column = -1;
|
||||
int line = -1, column = -1;
|
||||
int cursor_line = -1, cursor_column = -1;
|
||||
int tab_size = 4;
|
||||
|
||||
// Keep track of multichar tokens.
|
||||
const char32_t *_start = nullptr;
|
||||
int start_line = 0;
|
||||
int start_column = 0;
|
||||
int start_line = 0, start_column = 0;
|
||||
|
||||
// Info cache.
|
||||
bool line_continuation = false; // Whether this line is a continuation of the previous, like when using '\'.
|
||||
|
|
|
|||
|
|
@ -41,36 +41,36 @@
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
#define DEBUG_VALIDATE_ARG_COUNT(m_min_count, m_max_count) \
|
||||
if (unlikely(p_arg_count < m_min_count)) { \
|
||||
*r_ret = Variant(); \
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \
|
||||
r_error.expected = m_min_count; \
|
||||
return; \
|
||||
} \
|
||||
if (unlikely(p_arg_count > m_max_count)) { \
|
||||
*r_ret = Variant(); \
|
||||
#define DEBUG_VALIDATE_ARG_COUNT(m_min_count, m_max_count) \
|
||||
if (unlikely(p_arg_count < m_min_count)) { \
|
||||
*r_ret = Variant(); \
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \
|
||||
r_error.expected = m_min_count; \
|
||||
return; \
|
||||
} \
|
||||
if (unlikely(p_arg_count > m_max_count)) { \
|
||||
*r_ret = Variant(); \
|
||||
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \
|
||||
r_error.expected = m_max_count; \
|
||||
return; \
|
||||
r_error.expected = m_max_count; \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define DEBUG_VALIDATE_ARG_TYPE(m_arg, m_type) \
|
||||
#define DEBUG_VALIDATE_ARG_TYPE(m_arg, m_type) \
|
||||
if (unlikely(!Variant::can_convert_strict(p_args[m_arg]->get_type(), m_type))) { \
|
||||
*r_ret = Variant(); \
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
|
||||
r_error.argument = m_arg; \
|
||||
r_error.expected = m_type; \
|
||||
return; \
|
||||
*r_ret = Variant(); \
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
|
||||
r_error.argument = m_arg; \
|
||||
r_error.expected = m_type; \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define DEBUG_VALIDATE_ARG_CUSTOM(m_arg, m_type, m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
*r_ret = m_msg; \
|
||||
#define DEBUG_VALIDATE_ARG_CUSTOM(m_arg, m_type, m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
*r_ret = m_msg; \
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
|
||||
r_error.argument = m_arg; \
|
||||
r_error.expected = m_type; \
|
||||
return; \
|
||||
r_error.argument = m_arg; \
|
||||
r_error.expected = m_type; \
|
||||
return; \
|
||||
}
|
||||
|
||||
#else // !DEBUG_ENABLED
|
||||
|
|
@ -81,20 +81,20 @@
|
|||
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
#define VALIDATE_ARG_CUSTOM(m_arg, m_type, m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
*r_ret = m_msg; \
|
||||
#define VALIDATE_ARG_CUSTOM(m_arg, m_type, m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
*r_ret = m_msg; \
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
|
||||
r_error.argument = m_arg; \
|
||||
r_error.expected = m_type; \
|
||||
return; \
|
||||
r_error.argument = m_arg; \
|
||||
r_error.expected = m_type; \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define GDFUNC_FAIL_COND_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
*r_ret = m_msg; \
|
||||
#define GDFUNC_FAIL_COND_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
*r_ret = m_msg; \
|
||||
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; \
|
||||
return; \
|
||||
return; \
|
||||
}
|
||||
|
||||
struct GDScriptUtilityFunctionsDefinitions {
|
||||
|
|
@ -109,13 +109,13 @@ struct GDScriptUtilityFunctionsDefinitions {
|
|||
|
||||
Variant::construct(Variant::Type(type), *r_ret, p_args, 1, r_error);
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
static inline void type_exists(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
|
||||
DEBUG_VALIDATE_ARG_COUNT(1, 1);
|
||||
DEBUG_VALIDATE_ARG_TYPE(0, Variant::STRING_NAME);
|
||||
*r_ret = ClassDB::class_exists(*p_args[0]);
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
static inline void _char(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
|
||||
DEBUG_VALIDATE_ARG_COUNT(1, 1);
|
||||
|
|
@ -527,19 +527,19 @@ static void _register_function(const StringName &p_name, const MethodInfo &p_met
|
|||
utility_function_name_table.push_back(p_name);
|
||||
}
|
||||
|
||||
#define REGISTER_FUNC(m_func, m_is_const, m_return, m_args, m_is_vararg, m_default_args) \
|
||||
{ \
|
||||
String name(#m_func); \
|
||||
if (name.begins_with("_")) { \
|
||||
name = name.substr(1); \
|
||||
} \
|
||||
MethodInfo info = m_args; \
|
||||
info.name = name; \
|
||||
info.return_val = m_return; \
|
||||
info.default_arguments = m_default_args; \
|
||||
if (m_is_vararg) { \
|
||||
info.flags |= METHOD_FLAG_VARARG; \
|
||||
} \
|
||||
#define REGISTER_FUNC(m_func, m_is_const, m_return, m_args, m_is_vararg, m_default_args) \
|
||||
{ \
|
||||
String name(#m_func); \
|
||||
if (name.begins_with("_")) { \
|
||||
name = name.substr(1); \
|
||||
} \
|
||||
MethodInfo info = m_args; \
|
||||
info.name = name; \
|
||||
info.return_val = m_return; \
|
||||
info.default_arguments = m_default_args; \
|
||||
if (m_is_vararg) { \
|
||||
info.flags |= METHOD_FLAG_VARARG; \
|
||||
} \
|
||||
_register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \
|
||||
}
|
||||
|
||||
|
|
@ -571,8 +571,8 @@ void GDScriptUtilityFunctions::register_functions() {
|
|||
/* clang-format off */
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
REGISTER_FUNC( convert, true, RETVAR, ARGS( ARGVAR("what"), ARGTYPE("type") ), false, varray( ));
|
||||
REGISTER_FUNC( type_exists, true, RET(BOOL), ARGS( ARG("type", STRING_NAME) ), false, varray( ));
|
||||
#endif // DISABLE_DEPRECATED
|
||||
REGISTER_FUNC( type_exists, true, RET(BOOL), ARGS( ARG("type", STRING_NAME) ), false, varray( ));
|
||||
REGISTER_FUNC( _char, true, RET(STRING), ARGS( ARG("code", INT) ), false, varray( ));
|
||||
REGISTER_FUNC( ord, true, RET(INT), ARGS( ARG("char", STRING) ), false, varray( ));
|
||||
REGISTER_FUNC( range, false, RET(ARRAY), NOARGS, true, varray( ));
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
#include "gdscript_function.h"
|
||||
#include "gdscript_lambda_callable.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/profiling/profiling.h"
|
||||
|
||||
|
|
@ -252,167 +251,167 @@ void (*type_init_function_table[])(Variant *) = {
|
|||
};
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define OPCODES_TABLE \
|
||||
static const void *switch_table_ops[] = { \
|
||||
&&OPCODE_OPERATOR, \
|
||||
&&OPCODE_OPERATOR_VALIDATED, \
|
||||
&&OPCODE_TYPE_TEST_BUILTIN, \
|
||||
&&OPCODE_TYPE_TEST_ARRAY, \
|
||||
&&OPCODE_TYPE_TEST_DICTIONARY, \
|
||||
&&OPCODE_TYPE_TEST_NATIVE, \
|
||||
&&OPCODE_TYPE_TEST_SCRIPT, \
|
||||
&&OPCODE_SET_KEYED, \
|
||||
&&OPCODE_SET_KEYED_VALIDATED, \
|
||||
&&OPCODE_SET_INDEXED_VALIDATED, \
|
||||
&&OPCODE_GET_KEYED, \
|
||||
&&OPCODE_GET_KEYED_VALIDATED, \
|
||||
&&OPCODE_GET_INDEXED_VALIDATED, \
|
||||
&&OPCODE_SET_NAMED, \
|
||||
&&OPCODE_SET_NAMED_VALIDATED, \
|
||||
&&OPCODE_GET_NAMED, \
|
||||
&&OPCODE_GET_NAMED_VALIDATED, \
|
||||
&&OPCODE_SET_MEMBER, \
|
||||
&&OPCODE_GET_MEMBER, \
|
||||
&&OPCODE_SET_STATIC_VARIABLE, \
|
||||
&&OPCODE_GET_STATIC_VARIABLE, \
|
||||
&&OPCODE_ASSIGN, \
|
||||
&&OPCODE_ASSIGN_NULL, \
|
||||
&&OPCODE_ASSIGN_TRUE, \
|
||||
&&OPCODE_ASSIGN_FALSE, \
|
||||
&&OPCODE_ASSIGN_TYPED_BUILTIN, \
|
||||
&&OPCODE_ASSIGN_TYPED_ARRAY, \
|
||||
&&OPCODE_ASSIGN_TYPED_DICTIONARY, \
|
||||
&&OPCODE_ASSIGN_TYPED_NATIVE, \
|
||||
&&OPCODE_ASSIGN_TYPED_SCRIPT, \
|
||||
&&OPCODE_CAST_TO_BUILTIN, \
|
||||
&&OPCODE_CAST_TO_NATIVE, \
|
||||
&&OPCODE_CAST_TO_SCRIPT, \
|
||||
&&OPCODE_CONSTRUCT, \
|
||||
&&OPCODE_CONSTRUCT_VALIDATED, \
|
||||
&&OPCODE_CONSTRUCT_ARRAY, \
|
||||
&&OPCODE_CONSTRUCT_TYPED_ARRAY, \
|
||||
&&OPCODE_CONSTRUCT_DICTIONARY, \
|
||||
&&OPCODE_CONSTRUCT_TYPED_DICTIONARY, \
|
||||
&&OPCODE_CALL, \
|
||||
&&OPCODE_CALL_RETURN, \
|
||||
&&OPCODE_CALL_ASYNC, \
|
||||
&&OPCODE_CALL_UTILITY, \
|
||||
&&OPCODE_CALL_UTILITY_VALIDATED, \
|
||||
&&OPCODE_CALL_GDSCRIPT_UTILITY, \
|
||||
&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
|
||||
&&OPCODE_CALL_SELF_BASE, \
|
||||
&&OPCODE_CALL_METHOD_BIND, \
|
||||
&&OPCODE_CALL_METHOD_BIND_RET, \
|
||||
&&OPCODE_CALL_BUILTIN_STATIC, \
|
||||
&&OPCODE_CALL_NATIVE_STATIC, \
|
||||
&&OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN, \
|
||||
#define OPCODES_TABLE \
|
||||
static const void *switch_table_ops[] = { \
|
||||
&&OPCODE_OPERATOR, \
|
||||
&&OPCODE_OPERATOR_VALIDATED, \
|
||||
&&OPCODE_TYPE_TEST_BUILTIN, \
|
||||
&&OPCODE_TYPE_TEST_ARRAY, \
|
||||
&&OPCODE_TYPE_TEST_DICTIONARY, \
|
||||
&&OPCODE_TYPE_TEST_NATIVE, \
|
||||
&&OPCODE_TYPE_TEST_SCRIPT, \
|
||||
&&OPCODE_SET_KEYED, \
|
||||
&&OPCODE_SET_KEYED_VALIDATED, \
|
||||
&&OPCODE_SET_INDEXED_VALIDATED, \
|
||||
&&OPCODE_GET_KEYED, \
|
||||
&&OPCODE_GET_KEYED_VALIDATED, \
|
||||
&&OPCODE_GET_INDEXED_VALIDATED, \
|
||||
&&OPCODE_SET_NAMED, \
|
||||
&&OPCODE_SET_NAMED_VALIDATED, \
|
||||
&&OPCODE_GET_NAMED, \
|
||||
&&OPCODE_GET_NAMED_VALIDATED, \
|
||||
&&OPCODE_SET_MEMBER, \
|
||||
&&OPCODE_GET_MEMBER, \
|
||||
&&OPCODE_SET_STATIC_VARIABLE, \
|
||||
&&OPCODE_GET_STATIC_VARIABLE, \
|
||||
&&OPCODE_ASSIGN, \
|
||||
&&OPCODE_ASSIGN_NULL, \
|
||||
&&OPCODE_ASSIGN_TRUE, \
|
||||
&&OPCODE_ASSIGN_FALSE, \
|
||||
&&OPCODE_ASSIGN_TYPED_BUILTIN, \
|
||||
&&OPCODE_ASSIGN_TYPED_ARRAY, \
|
||||
&&OPCODE_ASSIGN_TYPED_DICTIONARY, \
|
||||
&&OPCODE_ASSIGN_TYPED_NATIVE, \
|
||||
&&OPCODE_ASSIGN_TYPED_SCRIPT, \
|
||||
&&OPCODE_CAST_TO_BUILTIN, \
|
||||
&&OPCODE_CAST_TO_NATIVE, \
|
||||
&&OPCODE_CAST_TO_SCRIPT, \
|
||||
&&OPCODE_CONSTRUCT, \
|
||||
&&OPCODE_CONSTRUCT_VALIDATED, \
|
||||
&&OPCODE_CONSTRUCT_ARRAY, \
|
||||
&&OPCODE_CONSTRUCT_TYPED_ARRAY, \
|
||||
&&OPCODE_CONSTRUCT_DICTIONARY, \
|
||||
&&OPCODE_CONSTRUCT_TYPED_DICTIONARY, \
|
||||
&&OPCODE_CALL, \
|
||||
&&OPCODE_CALL_RETURN, \
|
||||
&&OPCODE_CALL_ASYNC, \
|
||||
&&OPCODE_CALL_UTILITY, \
|
||||
&&OPCODE_CALL_UTILITY_VALIDATED, \
|
||||
&&OPCODE_CALL_GDSCRIPT_UTILITY, \
|
||||
&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
|
||||
&&OPCODE_CALL_SELF_BASE, \
|
||||
&&OPCODE_CALL_METHOD_BIND, \
|
||||
&&OPCODE_CALL_METHOD_BIND_RET, \
|
||||
&&OPCODE_CALL_BUILTIN_STATIC, \
|
||||
&&OPCODE_CALL_NATIVE_STATIC, \
|
||||
&&OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN, \
|
||||
&&OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN, \
|
||||
&&OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN, \
|
||||
&&OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, \
|
||||
&&OPCODE_AWAIT, \
|
||||
&&OPCODE_AWAIT_RESUME, \
|
||||
&&OPCODE_CREATE_LAMBDA, \
|
||||
&&OPCODE_CREATE_SELF_LAMBDA, \
|
||||
&&OPCODE_JUMP, \
|
||||
&&OPCODE_JUMP_IF, \
|
||||
&&OPCODE_JUMP_IF_NOT, \
|
||||
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
|
||||
&&OPCODE_JUMP_IF_SHARED, \
|
||||
&&OPCODE_RETURN, \
|
||||
&&OPCODE_RETURN_TYPED_BUILTIN, \
|
||||
&&OPCODE_RETURN_TYPED_ARRAY, \
|
||||
&&OPCODE_RETURN_TYPED_DICTIONARY, \
|
||||
&&OPCODE_RETURN_TYPED_NATIVE, \
|
||||
&&OPCODE_RETURN_TYPED_SCRIPT, \
|
||||
&&OPCODE_ITERATE_BEGIN, \
|
||||
&&OPCODE_ITERATE_BEGIN_INT, \
|
||||
&&OPCODE_ITERATE_BEGIN_FLOAT, \
|
||||
&&OPCODE_ITERATE_BEGIN_VECTOR2, \
|
||||
&&OPCODE_ITERATE_BEGIN_VECTOR2I, \
|
||||
&&OPCODE_ITERATE_BEGIN_VECTOR3, \
|
||||
&&OPCODE_ITERATE_BEGIN_VECTOR3I, \
|
||||
&&OPCODE_ITERATE_BEGIN_STRING, \
|
||||
&&OPCODE_ITERATE_BEGIN_DICTIONARY, \
|
||||
&&OPCODE_ITERATE_BEGIN_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR4_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_OBJECT, \
|
||||
&&OPCODE_ITERATE_BEGIN_RANGE, \
|
||||
&&OPCODE_ITERATE, \
|
||||
&&OPCODE_ITERATE_INT, \
|
||||
&&OPCODE_ITERATE_FLOAT, \
|
||||
&&OPCODE_ITERATE_VECTOR2, \
|
||||
&&OPCODE_ITERATE_VECTOR2I, \
|
||||
&&OPCODE_ITERATE_VECTOR3, \
|
||||
&&OPCODE_ITERATE_VECTOR3I, \
|
||||
&&OPCODE_ITERATE_STRING, \
|
||||
&&OPCODE_ITERATE_DICTIONARY, \
|
||||
&&OPCODE_ITERATE_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_BYTE_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_INT32_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_INT64_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_STRING_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_VECTOR4_ARRAY, \
|
||||
&&OPCODE_ITERATE_OBJECT, \
|
||||
&&OPCODE_ITERATE_RANGE, \
|
||||
&&OPCODE_STORE_GLOBAL, \
|
||||
&&OPCODE_STORE_NAMED_GLOBAL, \
|
||||
&&OPCODE_TYPE_ADJUST_BOOL, \
|
||||
&&OPCODE_TYPE_ADJUST_INT, \
|
||||
&&OPCODE_TYPE_ADJUST_FLOAT, \
|
||||
&&OPCODE_TYPE_ADJUST_STRING, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR2, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR2I, \
|
||||
&&OPCODE_TYPE_ADJUST_RECT2, \
|
||||
&&OPCODE_TYPE_ADJUST_RECT2I, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR3, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR3I, \
|
||||
&&OPCODE_TYPE_ADJUST_TRANSFORM2D, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR4, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR4I, \
|
||||
&&OPCODE_TYPE_ADJUST_PLANE, \
|
||||
&&OPCODE_TYPE_ADJUST_QUATERNION, \
|
||||
&&OPCODE_TYPE_ADJUST_AABB, \
|
||||
&&OPCODE_TYPE_ADJUST_BASIS, \
|
||||
&&OPCODE_TYPE_ADJUST_TRANSFORM3D, \
|
||||
&&OPCODE_TYPE_ADJUST_PROJECTION, \
|
||||
&&OPCODE_TYPE_ADJUST_COLOR, \
|
||||
&&OPCODE_TYPE_ADJUST_STRING_NAME, \
|
||||
&&OPCODE_TYPE_ADJUST_NODE_PATH, \
|
||||
&&OPCODE_TYPE_ADJUST_RID, \
|
||||
&&OPCODE_TYPE_ADJUST_OBJECT, \
|
||||
&&OPCODE_TYPE_ADJUST_CALLABLE, \
|
||||
&&OPCODE_TYPE_ADJUST_SIGNAL, \
|
||||
&&OPCODE_TYPE_ADJUST_DICTIONARY, \
|
||||
&&OPCODE_TYPE_ADJUST_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_VECTOR4_ARRAY, \
|
||||
&&OPCODE_ASSERT, \
|
||||
&&OPCODE_BREAKPOINT, \
|
||||
&&OPCODE_LINE, \
|
||||
&&OPCODE_END \
|
||||
}; \
|
||||
&&OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN, \
|
||||
&&OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, \
|
||||
&&OPCODE_AWAIT, \
|
||||
&&OPCODE_AWAIT_RESUME, \
|
||||
&&OPCODE_CREATE_LAMBDA, \
|
||||
&&OPCODE_CREATE_SELF_LAMBDA, \
|
||||
&&OPCODE_JUMP, \
|
||||
&&OPCODE_JUMP_IF, \
|
||||
&&OPCODE_JUMP_IF_NOT, \
|
||||
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
|
||||
&&OPCODE_JUMP_IF_SHARED, \
|
||||
&&OPCODE_RETURN, \
|
||||
&&OPCODE_RETURN_TYPED_BUILTIN, \
|
||||
&&OPCODE_RETURN_TYPED_ARRAY, \
|
||||
&&OPCODE_RETURN_TYPED_DICTIONARY, \
|
||||
&&OPCODE_RETURN_TYPED_NATIVE, \
|
||||
&&OPCODE_RETURN_TYPED_SCRIPT, \
|
||||
&&OPCODE_ITERATE_BEGIN, \
|
||||
&&OPCODE_ITERATE_BEGIN_INT, \
|
||||
&&OPCODE_ITERATE_BEGIN_FLOAT, \
|
||||
&&OPCODE_ITERATE_BEGIN_VECTOR2, \
|
||||
&&OPCODE_ITERATE_BEGIN_VECTOR2I, \
|
||||
&&OPCODE_ITERATE_BEGIN_VECTOR3, \
|
||||
&&OPCODE_ITERATE_BEGIN_VECTOR3I, \
|
||||
&&OPCODE_ITERATE_BEGIN_STRING, \
|
||||
&&OPCODE_ITERATE_BEGIN_DICTIONARY, \
|
||||
&&OPCODE_ITERATE_BEGIN_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR4_ARRAY, \
|
||||
&&OPCODE_ITERATE_BEGIN_OBJECT, \
|
||||
&&OPCODE_ITERATE_BEGIN_RANGE, \
|
||||
&&OPCODE_ITERATE, \
|
||||
&&OPCODE_ITERATE_INT, \
|
||||
&&OPCODE_ITERATE_FLOAT, \
|
||||
&&OPCODE_ITERATE_VECTOR2, \
|
||||
&&OPCODE_ITERATE_VECTOR2I, \
|
||||
&&OPCODE_ITERATE_VECTOR3, \
|
||||
&&OPCODE_ITERATE_VECTOR3I, \
|
||||
&&OPCODE_ITERATE_STRING, \
|
||||
&&OPCODE_ITERATE_DICTIONARY, \
|
||||
&&OPCODE_ITERATE_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_BYTE_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_INT32_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_INT64_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_STRING_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_VECTOR4_ARRAY, \
|
||||
&&OPCODE_ITERATE_OBJECT, \
|
||||
&&OPCODE_ITERATE_RANGE, \
|
||||
&&OPCODE_STORE_GLOBAL, \
|
||||
&&OPCODE_STORE_NAMED_GLOBAL, \
|
||||
&&OPCODE_TYPE_ADJUST_BOOL, \
|
||||
&&OPCODE_TYPE_ADJUST_INT, \
|
||||
&&OPCODE_TYPE_ADJUST_FLOAT, \
|
||||
&&OPCODE_TYPE_ADJUST_STRING, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR2, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR2I, \
|
||||
&&OPCODE_TYPE_ADJUST_RECT2, \
|
||||
&&OPCODE_TYPE_ADJUST_RECT2I, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR3, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR3I, \
|
||||
&&OPCODE_TYPE_ADJUST_TRANSFORM2D, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR4, \
|
||||
&&OPCODE_TYPE_ADJUST_VECTOR4I, \
|
||||
&&OPCODE_TYPE_ADJUST_PLANE, \
|
||||
&&OPCODE_TYPE_ADJUST_QUATERNION, \
|
||||
&&OPCODE_TYPE_ADJUST_AABB, \
|
||||
&&OPCODE_TYPE_ADJUST_BASIS, \
|
||||
&&OPCODE_TYPE_ADJUST_TRANSFORM3D, \
|
||||
&&OPCODE_TYPE_ADJUST_PROJECTION, \
|
||||
&&OPCODE_TYPE_ADJUST_COLOR, \
|
||||
&&OPCODE_TYPE_ADJUST_STRING_NAME, \
|
||||
&&OPCODE_TYPE_ADJUST_NODE_PATH, \
|
||||
&&OPCODE_TYPE_ADJUST_RID, \
|
||||
&&OPCODE_TYPE_ADJUST_OBJECT, \
|
||||
&&OPCODE_TYPE_ADJUST_CALLABLE, \
|
||||
&&OPCODE_TYPE_ADJUST_SIGNAL, \
|
||||
&&OPCODE_TYPE_ADJUST_DICTIONARY, \
|
||||
&&OPCODE_TYPE_ADJUST_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \
|
||||
&&OPCODE_TYPE_ADJUST_PACKED_VECTOR4_ARRAY, \
|
||||
&&OPCODE_ASSERT, \
|
||||
&&OPCODE_BREAKPOINT, \
|
||||
&&OPCODE_LINE, \
|
||||
&&OPCODE_END \
|
||||
}; \
|
||||
static_assert(std_size(switch_table_ops) == (OPCODE_END + 1), "Opcodes in jump table aren't the same as opcodes in enum.");
|
||||
|
||||
#define OPCODE(m_op) \
|
||||
|
|
@ -425,7 +424,7 @@ void (*type_init_function_table[])(Variant *) = {
|
|||
#define OPCODE_SWITCH(m_test) goto *switch_table_ops[m_test];
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define DISPATCH_OPCODE \
|
||||
#define DISPATCH_OPCODE \
|
||||
last_opcode = _code_ptr[ip]; \
|
||||
goto *switch_table_ops[last_opcode]
|
||||
#else // !DEBUG_ENABLED
|
||||
|
|
@ -443,7 +442,7 @@ void (*type_init_function_table[])(Variant *) = {
|
|||
#define DISPATCH_OPCODE continue
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define OPCODE_SWITCH(m_test) \
|
||||
#define OPCODE_SWITCH(m_test) \
|
||||
__assume(m_test <= OPCODE_END); \
|
||||
switch (m_test)
|
||||
#else // !_MSC_VER
|
||||
|
|
@ -543,9 +542,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
int line = _initial_line;
|
||||
|
||||
if (p_state) {
|
||||
// Use existing (supplied) state (awaited).
|
||||
//use existing (supplied) state (awaited)
|
||||
stack = (Variant *)p_state->stack.ptr();
|
||||
instruction_args = (Variant **)&p_state->stack.ptr()[sizeof(Variant) * p_state->stack_size]; // `ptr()` to avoid bounds check.
|
||||
instruction_args = (Variant **)&p_state->stack.ptr()[sizeof(Variant) * p_state->stack_size]; //ptr() to avoid bounds check
|
||||
line = p_state->line;
|
||||
ip = p_state->ip;
|
||||
alloca_size = p_state->stack.size();
|
||||
|
|
@ -553,11 +552,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
p_instance = p_state->instance;
|
||||
defarg = p_state->defarg;
|
||||
|
||||
// Responsibility for the stack is moved from `GDScriptFunctionState` to this method. So, we reset `p_state->stack_size`
|
||||
// to prevent `GDScriptFunctionState::_clear_stack()` from clearing the stack again.
|
||||
// NOTE: Strictly speaking, ownership doesn't move. However, we can be sure that `p_state->stack` won't be cleared
|
||||
// before the current call completes, and that `p_state` won't be resumed again.
|
||||
p_state->stack_size = 0;
|
||||
} else {
|
||||
if (p_argcount != _argument_count) {
|
||||
if (p_argcount > _argument_count) {
|
||||
|
|
@ -648,8 +642,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
instruction_args = nullptr;
|
||||
}
|
||||
|
||||
for (const Pair<int, Variant::Type> &E : temporary_slots) {
|
||||
type_init_function_table[E.second](&stack[E.first]);
|
||||
for (const KeyValue<int, Variant::Type> &E : temporary_slots) {
|
||||
type_init_function_table[E.value](&stack[E.key]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -660,11 +654,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
memnew_placement(&stack[ADDR_STACK_SELF], Variant);
|
||||
script = _script;
|
||||
}
|
||||
|
||||
// We must call a `Variant` constructor here, as accessing an object without doing so is undefined behavior.
|
||||
memnew_placement(&stack[ADDR_STACK_CLASS], Variant);
|
||||
VariantInternal::object_assign_without_ref_unsafe(&stack[ADDR_STACK_CLASS], script);
|
||||
|
||||
memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
|
||||
memnew_placement(&stack[ADDR_STACK_NIL], Variant);
|
||||
|
||||
String err_text;
|
||||
|
|
@ -673,61 +663,61 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
GDScriptLanguage::get_singleton()->enter_function(&call_level, p_instance, this, stack, &ip, &line);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define GD_ERR_BREAK(m_cond) \
|
||||
{ \
|
||||
if (unlikely(m_cond)) { \
|
||||
#define GD_ERR_BREAK(m_cond) \
|
||||
{ \
|
||||
if (unlikely(m_cond)) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:"); \
|
||||
OPCODE_BREAK; \
|
||||
} \
|
||||
OPCODE_BREAK; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECK_SPACE(m_space) \
|
||||
GD_ERR_BREAK((ip + m_space) > _code_size)
|
||||
|
||||
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
|
||||
Variant *m_v; \
|
||||
{ \
|
||||
int address = _code_ptr[ip + 1 + (m_code_ofs)]; \
|
||||
int address_type = (address & ADDR_TYPE_MASK) >> ADDR_BITS; \
|
||||
if (unlikely(address_type < 0 || address_type >= ADDR_TYPE_MAX)) { \
|
||||
err_text = "Bad address type."; \
|
||||
OPCODE_BREAK; \
|
||||
} \
|
||||
int address_index = address & ADDR_MASK; \
|
||||
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
|
||||
Variant *m_v; \
|
||||
{ \
|
||||
int address = _code_ptr[ip + 1 + (m_code_ofs)]; \
|
||||
int address_type = (address & ADDR_TYPE_MASK) >> ADDR_BITS; \
|
||||
if (unlikely(address_type < 0 || address_type >= ADDR_TYPE_MAX)) { \
|
||||
err_text = "Bad address type."; \
|
||||
OPCODE_BREAK; \
|
||||
} \
|
||||
int address_index = address & ADDR_MASK; \
|
||||
if (unlikely(address_index < 0 || address_index >= variant_address_limits[address_type])) { \
|
||||
if (address_type == ADDR_TYPE_MEMBER && !p_instance) { \
|
||||
err_text = "Cannot access member without instance."; \
|
||||
} else { \
|
||||
err_text = "Bad address index."; \
|
||||
} \
|
||||
OPCODE_BREAK; \
|
||||
} \
|
||||
m_v = &variant_addresses[address_type][address_index]; \
|
||||
if (unlikely(!m_v)) \
|
||||
OPCODE_BREAK; \
|
||||
if (address_type == ADDR_TYPE_MEMBER && !p_instance) { \
|
||||
err_text = "Cannot access member without instance."; \
|
||||
} else { \
|
||||
err_text = "Bad address index."; \
|
||||
} \
|
||||
OPCODE_BREAK; \
|
||||
} \
|
||||
m_v = &variant_addresses[address_type][address_index]; \
|
||||
if (unlikely(!m_v)) \
|
||||
OPCODE_BREAK; \
|
||||
}
|
||||
|
||||
#else // !DEBUG_ENABLED
|
||||
#define GD_ERR_BREAK(m_cond)
|
||||
#define CHECK_SPACE(m_space)
|
||||
|
||||
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
|
||||
Variant *m_v; \
|
||||
{ \
|
||||
int address = _code_ptr[ip + 1 + (m_code_ofs)]; \
|
||||
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
|
||||
Variant *m_v; \
|
||||
{ \
|
||||
int address = _code_ptr[ip + 1 + (m_code_ofs)]; \
|
||||
m_v = &variant_addresses[(address & ADDR_TYPE_MASK) >> ADDR_BITS][address & ADDR_MASK]; \
|
||||
if (unlikely(!m_v)) \
|
||||
OPCODE_BREAK; \
|
||||
if (unlikely(!m_v)) \
|
||||
OPCODE_BREAK; \
|
||||
}
|
||||
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
#define LOAD_INSTRUCTION_ARGS \
|
||||
int instr_arg_count = _code_ptr[ip + 1]; \
|
||||
#define LOAD_INSTRUCTION_ARGS \
|
||||
int instr_arg_count = _code_ptr[ip + 1]; \
|
||||
for (int i = 0; i < instr_arg_count; i++) { \
|
||||
GET_VARIANT_PTR(v, i + 1); \
|
||||
instruction_args[i] = v; \
|
||||
} \
|
||||
GET_VARIANT_PTR(v, i + 1); \
|
||||
instruction_args[i] = v; \
|
||||
} \
|
||||
ip += 1; // Offset to skip instruction argcount.
|
||||
|
||||
#define GET_INSTRUCTION_ARG(m_v, m_idx) \
|
||||
|
|
@ -2822,8 +2812,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
Variant::construct(ret_type, retvalue, const_cast<const Variant **>(&r), 1, ce);
|
||||
} else {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), Variant::get_type_name(ret_type));
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
Variant::get_type_name(r->get_type()), Variant::get_type_name(ret_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
// Construct a base type anyway so type constraints are met.
|
||||
|
|
@ -2852,9 +2842,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
|
||||
if (r->get_type() != Variant::ARRAY) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "Array[%s]".)",
|
||||
_get_var_type(r), Variant::get_type_name(builtin_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "Array[%s]".)",
|
||||
Variant::get_type_name(r->get_type()), Variant::get_type_name(builtin_type));
|
||||
#endif
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
||||
|
|
@ -2862,7 +2852,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
|
||||
if (array->get_typed_builtin() != ((uint32_t)builtin_type) || array->get_typed_class_name() != native_type || array->get_typed_script() != *script_type) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "Array[%s]".)",
|
||||
err_text = vformat(R"(Trying to return an array of type "%s" where expected return type is "Array[%s]".)",
|
||||
_get_var_type(r), _get_element_type(builtin_type, native_type, *script_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
|
|
@ -2894,7 +2884,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
|
||||
if (r->get_type() != Variant::DICTIONARY) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "Dictionary[%s, %s]".)",
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" where expected return type is "Dictionary[%s, %s]".)",
|
||||
_get_var_type(r), _get_element_type(key_builtin_type, key_native_type, *key_script_type),
|
||||
_get_element_type(value_builtin_type, value_native_type, *value_script_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
|
|
@ -2906,7 +2896,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
if (dictionary->get_typed_key_builtin() != ((uint32_t)key_builtin_type) || dictionary->get_typed_key_class_name() != key_native_type || dictionary->get_typed_key_script() != *key_script_type ||
|
||||
dictionary->get_typed_value_builtin() != ((uint32_t)value_builtin_type) || dictionary->get_typed_value_class_name() != value_native_type || dictionary->get_typed_value_script() != *value_script_type) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "Dictionary[%s, %s]".)",
|
||||
err_text = vformat(R"(Trying to return a dictionary of type "%s" where expected return type is "Dictionary[%s, %s]".)",
|
||||
_get_var_type(r), _get_element_type(key_builtin_type, key_native_type, *key_script_type),
|
||||
_get_element_type(value_builtin_type, value_native_type, *value_script_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
|
|
@ -2930,10 +2920,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
GD_ERR_BREAK(!nc);
|
||||
|
||||
if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), nc->get_name());
|
||||
#endif // DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
Variant::get_type_name(r->get_type()), nc->get_name());
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
||||
|
|
@ -2950,8 +2938,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
#endif // DEBUG_ENABLED
|
||||
if (ret_obj && !ClassDB::is_parent_class(ret_obj->get_class_name(), nc->get_name())) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), nc->get_name());
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
ret_obj->get_class_name(), nc->get_name());
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
|
@ -2973,8 +2961,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
|
||||
if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), GDScript::debug_get_script_name(Ref<Script>(base_type)));
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
Variant::get_type_name(r->get_type()), GDScript::debug_get_script_name(Ref<Script>(base_type)));
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
|
@ -2995,8 +2983,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
ScriptInstance *ret_inst = ret_obj->get_script_instance();
|
||||
if (!ret_inst) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), GDScript::debug_get_script_name(Ref<GDScript>(base_type)));
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
ret_obj->get_class_name(), GDScript::debug_get_script_name(Ref<GDScript>(base_type)));
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
|
@ -3014,8 +3002,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
|
||||
if (!valid) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), GDScript::debug_get_script_name(Ref<GDScript>(base_type)));
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
GDScript::debug_get_script_name(ret_obj->get_script_instance()->get_script()), GDScript::debug_get_script_name(Ref<GDScript>(base_type)));
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
|
@ -3313,25 +3301,25 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
DISPATCH_OPCODE;
|
||||
|
||||
#define OPCODE_ITERATE_BEGIN_PACKED_ARRAY(m_var_type, m_elem_type, m_get_func, m_var_ret_type, m_ret_type, m_ret_get_func) \
|
||||
OPCODE(OPCODE_ITERATE_BEGIN_PACKED_##m_var_type##_ARRAY) { \
|
||||
CHECK_SPACE(8); \
|
||||
GET_VARIANT_PTR(counter, 0); \
|
||||
GET_VARIANT_PTR(container, 1); \
|
||||
Vector<m_elem_type> *array = VariantInternal::m_get_func(container); \
|
||||
VariantInternal::initialize(counter, Variant::INT); \
|
||||
*VariantInternal::get_int(counter) = 0; \
|
||||
if (!array->is_empty()) { \
|
||||
GET_VARIANT_PTR(iterator, 2); \
|
||||
VariantInternal::initialize(iterator, Variant::m_var_ret_type); \
|
||||
m_ret_type *it = VariantInternal::m_ret_get_func(iterator); \
|
||||
*it = array->get(0); \
|
||||
ip += 5; \
|
||||
} else { \
|
||||
int jumpto = _code_ptr[ip + 4]; \
|
||||
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size); \
|
||||
ip = jumpto; \
|
||||
} \
|
||||
} \
|
||||
OPCODE(OPCODE_ITERATE_BEGIN_PACKED_##m_var_type##_ARRAY) { \
|
||||
CHECK_SPACE(8); \
|
||||
GET_VARIANT_PTR(counter, 0); \
|
||||
GET_VARIANT_PTR(container, 1); \
|
||||
Vector<m_elem_type> *array = VariantInternal::m_get_func(container); \
|
||||
VariantInternal::initialize(counter, Variant::INT); \
|
||||
*VariantInternal::get_int(counter) = 0; \
|
||||
if (!array->is_empty()) { \
|
||||
GET_VARIANT_PTR(iterator, 2); \
|
||||
VariantInternal::initialize(iterator, Variant::m_var_ret_type); \
|
||||
m_ret_type *it = VariantInternal::m_ret_get_func(iterator); \
|
||||
*it = array->get(0); \
|
||||
ip += 5; \
|
||||
} else { \
|
||||
int jumpto = _code_ptr[ip + 4]; \
|
||||
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size); \
|
||||
ip = jumpto; \
|
||||
} \
|
||||
} \
|
||||
DISPATCH_OPCODE
|
||||
|
||||
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(BYTE, uint8_t, get_byte_array, INT, int64_t, get_int);
|
||||
|
|
@ -3681,24 +3669,24 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
}
|
||||
DISPATCH_OPCODE;
|
||||
|
||||
#define OPCODE_ITERATE_PACKED_ARRAY(m_var_type, m_elem_type, m_get_func, m_ret_get_func) \
|
||||
OPCODE(OPCODE_ITERATE_PACKED_##m_var_type##_ARRAY) { \
|
||||
CHECK_SPACE(4); \
|
||||
GET_VARIANT_PTR(counter, 0); \
|
||||
GET_VARIANT_PTR(container, 1); \
|
||||
#define OPCODE_ITERATE_PACKED_ARRAY(m_var_type, m_elem_type, m_get_func, m_ret_get_func) \
|
||||
OPCODE(OPCODE_ITERATE_PACKED_##m_var_type##_ARRAY) { \
|
||||
CHECK_SPACE(4); \
|
||||
GET_VARIANT_PTR(counter, 0); \
|
||||
GET_VARIANT_PTR(container, 1); \
|
||||
const Vector<m_elem_type> *array = VariantInternal::m_get_func((const Variant *)container); \
|
||||
int64_t *idx = VariantInternal::get_int(counter); \
|
||||
(*idx)++; \
|
||||
if (*idx >= array->size()) { \
|
||||
int jumpto = _code_ptr[ip + 4]; \
|
||||
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size); \
|
||||
ip = jumpto; \
|
||||
} else { \
|
||||
GET_VARIANT_PTR(iterator, 2); \
|
||||
*VariantInternal::m_ret_get_func(iterator) = array->get(*idx); \
|
||||
ip += 5; \
|
||||
} \
|
||||
} \
|
||||
int64_t *idx = VariantInternal::get_int(counter); \
|
||||
(*idx)++; \
|
||||
if (*idx >= array->size()) { \
|
||||
int jumpto = _code_ptr[ip + 4]; \
|
||||
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size); \
|
||||
ip = jumpto; \
|
||||
} else { \
|
||||
GET_VARIANT_PTR(iterator, 2); \
|
||||
*VariantInternal::m_ret_get_func(iterator) = array->get(*idx); \
|
||||
ip += 5; \
|
||||
} \
|
||||
} \
|
||||
DISPATCH_OPCODE
|
||||
|
||||
OPCODE_ITERATE_PACKED_ARRAY(BYTE, uint8_t, get_byte_array, get_int);
|
||||
|
|
@ -3822,13 +3810,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
}
|
||||
DISPATCH_OPCODE;
|
||||
|
||||
#define OPCODE_TYPE_ADJUST(m_v_type, m_c_type) \
|
||||
OPCODE(OPCODE_TYPE_ADJUST_##m_v_type) { \
|
||||
CHECK_SPACE(2); \
|
||||
GET_VARIANT_PTR(arg, 0); \
|
||||
#define OPCODE_TYPE_ADJUST(m_v_type, m_c_type) \
|
||||
OPCODE(OPCODE_TYPE_ADJUST_##m_v_type) { \
|
||||
CHECK_SPACE(2); \
|
||||
GET_VARIANT_PTR(arg, 0); \
|
||||
VariantTypeAdjust<m_c_type>::adjust(arg); \
|
||||
ip += 2; \
|
||||
} \
|
||||
ip += 2; \
|
||||
} \
|
||||
DISPATCH_OPCODE
|
||||
|
||||
OPCODE_TYPE_ADJUST(BOOL, bool);
|
||||
|
|
@ -4011,14 +3999,15 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
// This ensures the call stack can be properly shown when using `await`, showing what resumed the function.
|
||||
if (!p_state || awaited) {
|
||||
GDScriptLanguage::get_singleton()->exit_function();
|
||||
|
||||
// Free stack, except reserved addresses.
|
||||
for (int i = FIXED_ADDRESSES_MAX; i < _stack_size; i++) {
|
||||
stack[i].~Variant();
|
||||
}
|
||||
}
|
||||
|
||||
// We deliberately avoid calling the destructor for `ADDR_STACK_CLASS`, since we initialized it
|
||||
// without incrementing any reference count that it might have.
|
||||
stack[ADDR_STACK_SELF].~Variant();
|
||||
stack[ADDR_STACK_NIL].~Variant();
|
||||
|
||||
for (int i = FIXED_ADDRESSES_MAX; i < _stack_size; i++) {
|
||||
// Always free reserved addresses, since they are never copied.
|
||||
for (int i = 0; i < FIXED_ADDRESSES_MAX; i++) {
|
||||
stack[i].~Variant();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include "gdscript_warning.h"
|
||||
|
||||
#include "core/object/property_info.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
|
|
|||
|
|
@ -32,11 +32,10 @@
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/vector.h"
|
||||
|
||||
class String;
|
||||
struct PropertyInfo;
|
||||
|
||||
class GDScriptWarning {
|
||||
public:
|
||||
enum WarnLevel {
|
||||
|
|
@ -159,10 +158,7 @@ public:
|
|||
static_assert(std_size(default_warning_levels) == WARNING_MAX, "Amount of default levels does not match the amount of warnings.");
|
||||
|
||||
Code code = WARNING_MAX;
|
||||
int start_line = 0;
|
||||
int start_column = 0;
|
||||
int end_line = 0;
|
||||
int end_column = 0;
|
||||
int start_line = -1, end_line = -1;
|
||||
Vector<String> symbols;
|
||||
|
||||
String get_name() const;
|
||||
|
|
|
|||
|
|
@ -32,11 +32,10 @@
|
|||
|
||||
#include "../gdscript.h"
|
||||
#include "../gdscript_analyzer.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "gdscript_language_protocol.h"
|
||||
#include "gdscript_workspace.h"
|
||||
|
||||
#include "editor/settings/editor_settings.h"
|
||||
|
||||
int get_indent_size() {
|
||||
if (EditorSettings::get_singleton()) {
|
||||
return EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size");
|
||||
|
|
@ -136,12 +135,18 @@ void ExtendGDScriptParser::update_diagnostics() {
|
|||
diagnostic.severity = LSP::DiagnosticSeverity::Error;
|
||||
diagnostic.message = error.message;
|
||||
diagnostic.source = "gdscript";
|
||||
|
||||
GodotRange godot_range(
|
||||
GodotPosition(error.start_line, error.start_column),
|
||||
GodotPosition(error.end_line, error.end_column));
|
||||
|
||||
diagnostic.range = godot_range.to_lsp(get_lines());
|
||||
diagnostic.code = -1;
|
||||
LSP::Range range;
|
||||
LSP::Position pos;
|
||||
const PackedStringArray line_array = get_lines();
|
||||
int line = CLAMP(LINE_NUMBER_TO_INDEX(error.line), 0, line_array.size() - 1);
|
||||
const String &line_text = line_array[line];
|
||||
pos.line = line;
|
||||
pos.character = line_text.length() - line_text.strip_edges(true, false).length();
|
||||
range.start = pos;
|
||||
range.end = range.start;
|
||||
range.end.character = line_text.strip_edges(false).length();
|
||||
diagnostic.range = range;
|
||||
diagnostics.push_back(diagnostic);
|
||||
}
|
||||
|
||||
|
|
@ -151,12 +156,17 @@ void ExtendGDScriptParser::update_diagnostics() {
|
|||
diagnostic.severity = LSP::DiagnosticSeverity::Warning;
|
||||
diagnostic.message = "(" + warning.get_name() + "): " + warning.get_message();
|
||||
diagnostic.source = "gdscript";
|
||||
|
||||
GodotRange godot_range(
|
||||
GodotPosition(warning.start_line, warning.start_column),
|
||||
GodotPosition(warning.end_line, warning.end_column));
|
||||
|
||||
diagnostic.range = godot_range.to_lsp(get_lines());
|
||||
diagnostic.code = warning.code;
|
||||
LSP::Range range;
|
||||
LSP::Position pos;
|
||||
int line = LINE_NUMBER_TO_INDEX(warning.start_line);
|
||||
const String &line_text = get_lines()[line];
|
||||
pos.line = line;
|
||||
pos.character = line_text.length() - line_text.strip_edges(true, false).length();
|
||||
range.start = pos;
|
||||
range.end = pos;
|
||||
range.end.character = line_text.strip_edges(false).length();
|
||||
diagnostic.range = range;
|
||||
diagnostics.push_back(diagnostic);
|
||||
}
|
||||
}
|
||||
|
|
@ -860,6 +870,30 @@ const List<LSP::DocumentLink> &ExtendGDScriptParser::get_document_links() const
|
|||
return document_links;
|
||||
}
|
||||
|
||||
const Array &ExtendGDScriptParser::get_member_completions() {
|
||||
if (member_completions.is_empty()) {
|
||||
for (const KeyValue<String, const LSP::DocumentSymbol *> &E : members) {
|
||||
const LSP::DocumentSymbol *symbol = E.value;
|
||||
LSP::CompletionItem item = symbol->make_completion_item();
|
||||
item.data = JOIN_SYMBOLS(path, E.key);
|
||||
member_completions.push_back(item.to_json());
|
||||
}
|
||||
|
||||
for (const KeyValue<String, ClassMembers> &E : inner_classes) {
|
||||
const ClassMembers *inner_class = &E.value;
|
||||
|
||||
for (const KeyValue<String, const LSP::DocumentSymbol *> &F : *inner_class) {
|
||||
const LSP::DocumentSymbol *symbol = F.value;
|
||||
LSP::CompletionItem item = symbol->make_completion_item();
|
||||
item.data = JOIN_SYMBOLS(path, JOIN_SYMBOLS(E.key, F.key));
|
||||
member_completions.push_back(item.to_json());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return member_completions;
|
||||
}
|
||||
|
||||
Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::FunctionNode *p_func) const {
|
||||
ERR_FAIL_NULL_V(p_func, Dictionary());
|
||||
Dictionary func;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,14 @@
|
|||
#define COLUMN_NUMBER_TO_INDEX(p_column) ((p_column) - 1)
|
||||
#endif
|
||||
|
||||
#ifndef SYMBOL_SEPARATOR
|
||||
#define SYMBOL_SEPARATOR "::"
|
||||
#endif
|
||||
|
||||
#ifndef JOIN_SYMBOLS
|
||||
#define JOIN_SYMBOLS(p_path, name) ((p_path) + SYMBOL_SEPARATOR + (name))
|
||||
#endif
|
||||
|
||||
typedef HashMap<String, const LSP::DocumentSymbol *> ClassMembers;
|
||||
|
||||
/**
|
||||
|
|
@ -126,6 +134,8 @@ class ExtendGDScriptParser : public GDScriptParser {
|
|||
|
||||
const LSP::DocumentSymbol *search_symbol_defined_at_line(int p_line, const LSP::DocumentSymbol &p_parent, const String &p_symbol_name = "") const;
|
||||
|
||||
Array member_completions;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ const String &get_path() const { return path; }
|
||||
_FORCE_INLINE_ const Vector<String> &get_lines() const { return lines; }
|
||||
|
|
|
|||
|
|
@ -30,27 +30,23 @@
|
|||
|
||||
#include "gdscript_language_protocol.h"
|
||||
|
||||
#include "godot_lsp.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/os/os.h"
|
||||
#include "editor/doc/doc_tools.h"
|
||||
#include "editor/doc/editor_help.h"
|
||||
#include "editor/editor_log.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "modules/gdscript/language_server/godot_lsp.h"
|
||||
|
||||
#define LSP_CLIENT_V(m_ret_val) \
|
||||
#define LSP_CLIENT_V(m_ret_val) \
|
||||
ERR_FAIL_COND_V(latest_client_id == LSP_NO_CLIENT, m_ret_val); \
|
||||
ERR_FAIL_COND_V(!clients.has(latest_client_id), m_ret_val); \
|
||||
Ref<LSPeer> client = clients.get(latest_client_id); \
|
||||
ERR_FAIL_COND_V(!clients.has(latest_client_id), m_ret_val); \
|
||||
Ref<LSPeer> client = clients.get(latest_client_id); \
|
||||
ERR_FAIL_COND_V(!client.is_valid(), m_ret_val);
|
||||
|
||||
#define LSP_CLIENT \
|
||||
ERR_FAIL_COND(latest_client_id == LSP_NO_CLIENT); \
|
||||
ERR_FAIL_COND(!clients.has(latest_client_id)); \
|
||||
#define LSP_CLIENT \
|
||||
ERR_FAIL_COND(latest_client_id == LSP_NO_CLIENT); \
|
||||
ERR_FAIL_COND(!clients.has(latest_client_id)); \
|
||||
Ref<LSPeer> client = clients.get(latest_client_id); \
|
||||
ERR_FAIL_COND(!client.is_valid());
|
||||
|
||||
|
|
@ -152,9 +148,6 @@ Error GDScriptLanguageProtocol::on_client_connected() {
|
|||
|
||||
void GDScriptLanguageProtocol::on_client_disconnected(const int &p_client_id) {
|
||||
clients.erase(p_client_id);
|
||||
if (clients.is_empty()) {
|
||||
scene_cache.clear();
|
||||
}
|
||||
EditorNode::get_log()->add_message("[LSP] Disconnected", EditorLog::MSG_TYPE_EDITOR);
|
||||
}
|
||||
|
||||
|
|
@ -178,18 +171,15 @@ String GDScriptLanguageProtocol::format_output(const String &p_text) {
|
|||
}
|
||||
|
||||
void GDScriptLanguageProtocol::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_text_document"), &GDScriptLanguageProtocol::get_text_document);
|
||||
ClassDB::bind_method(D_METHOD("get_workspace"), &GDScriptLanguageProtocol::get_workspace);
|
||||
ClassDB::bind_method(D_METHOD("is_smart_resolve_enabled"), &GDScriptLanguageProtocol::is_smart_resolve_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_initialized"), &GDScriptLanguageProtocol::is_initialized);
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
ClassDB::bind_method(D_METHOD("initialize", "params"), &GDScriptLanguageProtocol::initialize);
|
||||
ClassDB::bind_method(D_METHOD("initialized", "params"), &GDScriptLanguageProtocol::initialized);
|
||||
ClassDB::bind_method(D_METHOD("on_client_connected"), &GDScriptLanguageProtocol::on_client_connected);
|
||||
ClassDB::bind_method(D_METHOD("on_client_disconnected", "client_id"), &GDScriptLanguageProtocol::on_client_disconnected);
|
||||
ClassDB::bind_method(D_METHOD("on_client_disconnected"), &GDScriptLanguageProtocol::on_client_disconnected);
|
||||
ClassDB::bind_method(D_METHOD("notify_client", "method", "params", "client_id"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1));
|
||||
#endif // !DISABLE_DEPRECATED
|
||||
ClassDB::bind_method(D_METHOD("is_smart_resolve_enabled"), &GDScriptLanguageProtocol::is_smart_resolve_enabled);
|
||||
ClassDB::bind_method(D_METHOD("get_text_document"), &GDScriptLanguageProtocol::get_text_document);
|
||||
ClassDB::bind_method(D_METHOD("get_workspace"), &GDScriptLanguageProtocol::get_workspace);
|
||||
ClassDB::bind_method(D_METHOD("is_initialized"), &GDScriptLanguageProtocol::is_initialized);
|
||||
}
|
||||
|
||||
Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
|
||||
|
|
@ -249,6 +239,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
|
|||
|
||||
if (!_initialized) {
|
||||
workspace->initialize();
|
||||
text_document->initialize();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
|
|
@ -279,8 +270,6 @@ void GDScriptLanguageProtocol::poll(int p_limit_usec) {
|
|||
on_client_connected();
|
||||
}
|
||||
|
||||
scene_cache.poll();
|
||||
|
||||
HashMap<int, Ref<LSPeer>>::Iterator E = clients.begin();
|
||||
while (E != clients.end()) {
|
||||
Ref<LSPeer> peer = E->value;
|
||||
|
|
@ -327,7 +316,6 @@ void GDScriptLanguageProtocol::stop() {
|
|||
peer->connection->disconnect_from_host();
|
||||
}
|
||||
|
||||
scene_cache.clear();
|
||||
server->stop();
|
||||
}
|
||||
|
||||
|
|
@ -460,8 +448,6 @@ void GDScriptLanguageProtocol::lsp_did_open(const Dictionary &p_params) {
|
|||
|
||||
client->managed_files[path] = document;
|
||||
client->parse_script(path);
|
||||
|
||||
scene_cache.request_load(path);
|
||||
}
|
||||
|
||||
void GDScriptLanguageProtocol::lsp_did_change(const Dictionary &p_params) {
|
||||
|
|
@ -507,8 +493,6 @@ void GDScriptLanguageProtocol::lsp_did_close(const Dictionary &p_params) {
|
|||
|
||||
/// A close notification requires a previous open notification to be sent.
|
||||
ERR_FAIL_COND_MSG(!was_opened, "LSP: Client is closing file without opening it.");
|
||||
|
||||
scene_cache.unload(path);
|
||||
}
|
||||
|
||||
void GDScriptLanguageProtocol::resolve_related_symbols(const LSP::TextDocumentPositionParams &p_doc_pos, List<const LSP::DocumentSymbol *> &r_list) {
|
||||
|
|
@ -574,7 +558,6 @@ GDScriptLanguageProtocol::GDScriptLanguageProtocol() {
|
|||
SET_DOCUMENT_METHOD(didSave);
|
||||
|
||||
SET_DOCUMENT_METHOD(documentSymbol);
|
||||
SET_DOCUMENT_METHOD(documentHighlight);
|
||||
SET_DOCUMENT_METHOD(completion);
|
||||
SET_DOCUMENT_METHOD(rename);
|
||||
SET_DOCUMENT_METHOD(prepareRename);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
#include "gdscript_text_document.h"
|
||||
#include "gdscript_workspace.h"
|
||||
#include "scene_cache.h"
|
||||
|
||||
#include "core/io/stream_peer_tcp.h"
|
||||
#include "core/io/tcp_server.h"
|
||||
|
|
@ -47,7 +46,9 @@
|
|||
class GDScriptLanguageProtocol : public JSONRPC {
|
||||
GDCLASS(GDScriptLanguageProtocol, JSONRPC)
|
||||
|
||||
#ifdef TESTS_ENABLED
|
||||
friend class TestGDScriptLanguageProtocolInitializer;
|
||||
#endif
|
||||
|
||||
private:
|
||||
struct LSPeer : RefCounted {
|
||||
|
|
@ -91,7 +92,6 @@ private:
|
|||
static GDScriptLanguageProtocol *singleton;
|
||||
|
||||
HashMap<int, Ref<LSPeer>> clients;
|
||||
SceneCache scene_cache;
|
||||
Ref<TCPServer> server;
|
||||
int latest_client_id = LSP_NO_CLIENT;
|
||||
int next_client_id = 0;
|
||||
|
|
@ -119,8 +119,6 @@ public:
|
|||
_FORCE_INLINE_ static GDScriptLanguageProtocol *get_singleton() { return singleton; }
|
||||
_FORCE_INLINE_ Ref<GDScriptWorkspace> get_workspace() { return workspace; }
|
||||
_FORCE_INLINE_ Ref<GDScriptTextDocument> get_text_document() { return text_document; }
|
||||
_FORCE_INLINE_ SceneCache *get_scene_cache() { return &scene_cache; }
|
||||
|
||||
_FORCE_INLINE_ bool is_initialized() const { return _initialized; }
|
||||
|
||||
void poll(int p_limit_usec);
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include "gdscript_language_server.h"
|
||||
|
||||
#include "gdscript_language_protocol.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "editor/editor_log.h"
|
||||
#include "editor/editor_node.h"
|
||||
|
|
@ -40,6 +38,14 @@
|
|||
int GDScriptLanguageServer::port_override = -1;
|
||||
|
||||
GDScriptLanguageServer::GDScriptLanguageServer() {
|
||||
// TODO: Move to editor_settings.cpp
|
||||
_EDITOR_DEF("network/language_server/remote_host", host);
|
||||
_EDITOR_DEF("network/language_server/remote_port", port);
|
||||
_EDITOR_DEF("network/language_server/enable_smart_resolve", true);
|
||||
_EDITOR_DEF("network/language_server/show_native_symbols_in_editor", false);
|
||||
_EDITOR_DEF("network/language_server/use_thread", use_thread);
|
||||
_EDITOR_DEF("network/language_server/poll_limit_usec", poll_limit_usec);
|
||||
|
||||
set_process_internal(true);
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +62,7 @@ void GDScriptLanguageServer::_notification(int p_what) {
|
|||
}
|
||||
|
||||
if (started && !use_thread) {
|
||||
GDScriptLanguageProtocol::get_singleton()->poll(poll_limit_usec);
|
||||
protocol.poll(poll_limit_usec);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
@ -82,7 +88,7 @@ void GDScriptLanguageServer::thread_main(void *p_userdata) {
|
|||
GDScriptLanguageServer *self = static_cast<GDScriptLanguageServer *>(p_userdata);
|
||||
while (self->thread_running) {
|
||||
// Poll 20 times per second
|
||||
GDScriptLanguageProtocol::get_singleton()->poll(self->poll_limit_usec);
|
||||
self->protocol.poll(self->poll_limit_usec);
|
||||
OS::get_singleton()->delay_usec(50000);
|
||||
}
|
||||
}
|
||||
|
|
@ -92,18 +98,15 @@ void GDScriptLanguageServer::start() {
|
|||
port = (GDScriptLanguageServer::port_override > -1) ? GDScriptLanguageServer::port_override : (int)_EDITOR_GET("network/language_server/remote_port");
|
||||
use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
|
||||
poll_limit_usec = (int)_EDITOR_GET("network/language_server/poll_limit_usec");
|
||||
const Error status = GDScriptLanguageProtocol::get_singleton()->start(port, IPAddress(host));
|
||||
if (status != OK) {
|
||||
EditorNode::get_log()->add_message("--- Failed to start GDScript language server on port " + itos(port) + ": " + error_names[status] + " ---", EditorLog::MSG_TYPE_EDITOR);
|
||||
return;
|
||||
if (protocol.start(port, IPAddress(host)) == OK) {
|
||||
EditorNode::get_log()->add_message("--- GDScript language server started on port " + itos(port) + " ---", EditorLog::MSG_TYPE_EDITOR);
|
||||
if (use_thread) {
|
||||
thread_running = true;
|
||||
thread.start(GDScriptLanguageServer::thread_main, this);
|
||||
}
|
||||
set_process_internal(!use_thread);
|
||||
started = true;
|
||||
}
|
||||
EditorNode::get_log()->add_message("--- GDScript language server started on port " + itos(port) + " ---", EditorLog::MSG_TYPE_EDITOR);
|
||||
if (use_thread) {
|
||||
thread_running = true;
|
||||
thread.start(GDScriptLanguageServer::thread_main, this);
|
||||
}
|
||||
set_process_internal(!use_thread);
|
||||
started = true;
|
||||
}
|
||||
|
||||
void GDScriptLanguageServer::stop() {
|
||||
|
|
@ -112,7 +115,7 @@ void GDScriptLanguageServer::stop() {
|
|||
thread_running = false;
|
||||
thread.wait_to_finish();
|
||||
}
|
||||
GDScriptLanguageProtocol::get_singleton()->stop();
|
||||
protocol.stop();
|
||||
started = false;
|
||||
EditorNode::get_log()->add_message("--- GDScript language server stopped ---", EditorLog::MSG_TYPE_EDITOR);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,23 +30,24 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "gdscript_language_protocol.h"
|
||||
|
||||
#include "editor/plugins/editor_plugin.h"
|
||||
|
||||
class GDScriptLanguageServer : public EditorPlugin {
|
||||
GDCLASS(GDScriptLanguageServer, EditorPlugin);
|
||||
|
||||
GDScriptLanguageProtocol protocol;
|
||||
|
||||
Thread thread;
|
||||
bool thread_running = false;
|
||||
// There is no notification when the editor is initialized. We need to poll till we attempted to start the server.
|
||||
bool start_attempted = false;
|
||||
bool started = false;
|
||||
|
||||
// Defaults located in editor_settings.cpp
|
||||
bool use_thread = false;
|
||||
String host;
|
||||
int port = 0;
|
||||
int poll_limit_usec = 0;
|
||||
|
||||
String host = "127.0.0.1";
|
||||
int port = 6005;
|
||||
int poll_limit_usec = 100000;
|
||||
static void thread_main(void *p_userdata);
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -34,38 +34,32 @@
|
|||
#include "gdscript_extend_parser.h"
|
||||
#include "gdscript_language_protocol.h"
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "editor/script/script_editor_plugin.h"
|
||||
#include "editor/script/script_text_editor.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "servers/display/display_server.h"
|
||||
|
||||
void GDScriptTextDocument::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("show_native_symbol_in_editor", "symbol_id"), &GDScriptTextDocument::show_native_symbol_in_editor);
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
ClassDB::bind_method(D_METHOD("didOpen", "params"), &GDScriptTextDocument::didOpen);
|
||||
ClassDB::bind_method(D_METHOD("didClose", "params"), &GDScriptTextDocument::didClose);
|
||||
ClassDB::bind_method(D_METHOD("didChange", "params"), &GDScriptTextDocument::didChange);
|
||||
ClassDB::bind_method(D_METHOD("willSaveWaitUntil", "params"), &GDScriptTextDocument::willSaveWaitUntil);
|
||||
ClassDB::bind_method(D_METHOD("didSave", "params"), &GDScriptTextDocument::didSave);
|
||||
ClassDB::bind_method(D_METHOD("nativeSymbol", "params"), &GDScriptTextDocument::nativeSymbol);
|
||||
ClassDB::bind_method(D_METHOD("documentSymbol", "params"), &GDScriptTextDocument::documentSymbol);
|
||||
ClassDB::bind_method(D_METHOD("completion", "params"), &GDScriptTextDocument::completion);
|
||||
ClassDB::bind_method(D_METHOD("resolve", "params"), &GDScriptTextDocument::resolve);
|
||||
ClassDB::bind_method(D_METHOD("rename", "params"), &GDScriptTextDocument::rename);
|
||||
ClassDB::bind_method(D_METHOD("prepareRename", "params"), &GDScriptTextDocument::prepareRename);
|
||||
ClassDB::bind_method(D_METHOD("references", "params"), &GDScriptTextDocument::references);
|
||||
ClassDB::bind_method(D_METHOD("foldingRange", "params"), &GDScriptTextDocument::foldingRange);
|
||||
ClassDB::bind_method(D_METHOD("codeLens", "params"), &GDScriptTextDocument::codeLens);
|
||||
ClassDB::bind_method(D_METHOD("documentLink", "params"), &GDScriptTextDocument::documentLink);
|
||||
ClassDB::bind_method(D_METHOD("colorPresentation", "params"), &GDScriptTextDocument::colorPresentation);
|
||||
ClassDB::bind_method(D_METHOD("hover", "params"), &GDScriptTextDocument::hover);
|
||||
ClassDB::bind_method(D_METHOD("definition", "params"), &GDScriptTextDocument::definition);
|
||||
ClassDB::bind_method(D_METHOD("declaration", "params"), &GDScriptTextDocument::declaration);
|
||||
ClassDB::bind_method(D_METHOD("signatureHelp", "params"), &GDScriptTextDocument::signatureHelp);
|
||||
#endif // !DISABLE_DEPRECATED
|
||||
ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen);
|
||||
ClassDB::bind_method(D_METHOD("didClose"), &GDScriptTextDocument::didClose);
|
||||
ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange);
|
||||
ClassDB::bind_method(D_METHOD("willSaveWaitUntil"), &GDScriptTextDocument::willSaveWaitUntil);
|
||||
ClassDB::bind_method(D_METHOD("didSave"), &GDScriptTextDocument::didSave);
|
||||
ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol);
|
||||
ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol);
|
||||
ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion);
|
||||
ClassDB::bind_method(D_METHOD("resolve"), &GDScriptTextDocument::resolve);
|
||||
ClassDB::bind_method(D_METHOD("rename"), &GDScriptTextDocument::rename);
|
||||
ClassDB::bind_method(D_METHOD("prepareRename"), &GDScriptTextDocument::prepareRename);
|
||||
ClassDB::bind_method(D_METHOD("references"), &GDScriptTextDocument::references);
|
||||
ClassDB::bind_method(D_METHOD("foldingRange"), &GDScriptTextDocument::foldingRange);
|
||||
ClassDB::bind_method(D_METHOD("codeLens"), &GDScriptTextDocument::codeLens);
|
||||
ClassDB::bind_method(D_METHOD("documentLink"), &GDScriptTextDocument::documentLink);
|
||||
ClassDB::bind_method(D_METHOD("colorPresentation"), &GDScriptTextDocument::colorPresentation);
|
||||
ClassDB::bind_method(D_METHOD("hover"), &GDScriptTextDocument::hover);
|
||||
ClassDB::bind_method(D_METHOD("definition"), &GDScriptTextDocument::definition);
|
||||
ClassDB::bind_method(D_METHOD("declaration"), &GDScriptTextDocument::declaration);
|
||||
ClassDB::bind_method(D_METHOD("signatureHelp"), &GDScriptTextDocument::signatureHelp);
|
||||
ClassDB::bind_method(D_METHOD("show_native_symbol_in_editor"), &GDScriptTextDocument::show_native_symbol_in_editor);
|
||||
}
|
||||
|
||||
void GDScriptTextDocument::didOpen(const Variant &p_param) {
|
||||
|
|
@ -128,6 +122,21 @@ void GDScriptTextDocument::notify_client_show_symbol(const LSP::DocumentSymbol *
|
|||
GDScriptLanguageProtocol::get_singleton()->notify_client("gdscript/show_native_symbol", symbol->to_json(true));
|
||||
}
|
||||
|
||||
void GDScriptTextDocument::initialize() {
|
||||
if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
|
||||
for (const KeyValue<StringName, ClassMembers> &E : GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members) {
|
||||
const ClassMembers &members = E.value;
|
||||
|
||||
for (const KeyValue<String, const LSP::DocumentSymbol *> &F : members) {
|
||||
const LSP::DocumentSymbol *symbol = members.get(F.key);
|
||||
LSP::CompletionItem item = symbol->make_completion_item();
|
||||
item.data = JOIN_SYMBOLS(String(E.key), F.key);
|
||||
native_member_completions.push_back(item.to_json());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Variant GDScriptTextDocument::nativeSymbol(const Dictionary &p_params) {
|
||||
Variant ret;
|
||||
|
||||
|
|
@ -156,25 +165,6 @@ Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) {
|
|||
return arr;
|
||||
}
|
||||
|
||||
Array GDScriptTextDocument::documentHighlight(const Dictionary &p_params) {
|
||||
Array arr;
|
||||
LSP::TextDocumentPositionParams params;
|
||||
params.load(p_params);
|
||||
|
||||
const LSP::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params);
|
||||
if (symbol) {
|
||||
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(params.textDocument.uri);
|
||||
Vector<LSP::Location> usages = GDScriptLanguageProtocol::get_singleton()->get_workspace()->find_usages_in_file(*symbol, path);
|
||||
|
||||
for (const LSP::Location &usage : usages) {
|
||||
LSP::DocumentHighlight highlight;
|
||||
highlight.range = usage.range;
|
||||
arr.push_back(highlight.to_json());
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
Array GDScriptTextDocument::completion(const Dictionary &p_params) {
|
||||
Array arr;
|
||||
|
||||
|
|
@ -299,6 +289,33 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
|
|||
if (data.get_type() == Variant::DICTIONARY) {
|
||||
params.load(p_params["data"]);
|
||||
symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params, item.label, item.kind == LSP::CompletionItemKind::Method || item.kind == LSP::CompletionItemKind::Function);
|
||||
|
||||
} else if (data.is_string()) {
|
||||
String query = data;
|
||||
|
||||
Vector<String> param_symbols = query.split(SYMBOL_SEPARATOR, false);
|
||||
|
||||
if (param_symbols.size() >= 2) {
|
||||
StringName class_name = param_symbols[0];
|
||||
const String &member_name = param_symbols[param_symbols.size() - 1];
|
||||
String inner_class_name;
|
||||
if (param_symbols.size() >= 3) {
|
||||
inner_class_name = param_symbols[1];
|
||||
}
|
||||
|
||||
if (const ClassMembers *members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members.getptr(class_name)) {
|
||||
if (const LSP::DocumentSymbol *const *member = members->getptr(member_name)) {
|
||||
symbol = *member;
|
||||
}
|
||||
}
|
||||
|
||||
if (!symbol) {
|
||||
ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(class_name);
|
||||
if (parser) {
|
||||
symbol = parser->get_member_symbol(member_name, inner_class_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol) {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ protected:
|
|||
|
||||
Ref<FileAccess> file_checker;
|
||||
|
||||
Array native_member_completions;
|
||||
|
||||
private:
|
||||
Array find_symbols(const LSP::TextDocumentPositionParams &p_location, List<const LSP::DocumentSymbol *> &r_list);
|
||||
void notify_client_show_symbol(const LSP::DocumentSymbol *symbol);
|
||||
|
|
@ -60,7 +62,6 @@ public:
|
|||
|
||||
Variant nativeSymbol(const Dictionary &p_params);
|
||||
Array documentSymbol(const Dictionary &p_params);
|
||||
Array documentHighlight(const Dictionary &p_params);
|
||||
Array completion(const Dictionary &p_params);
|
||||
Dictionary resolve(const Dictionary &p_params);
|
||||
Dictionary rename(const Dictionary &p_params);
|
||||
|
|
@ -75,5 +76,7 @@ public:
|
|||
Variant declaration(const Dictionary &p_params);
|
||||
Variant signatureHelp(const Dictionary &p_params);
|
||||
|
||||
void initialize();
|
||||
|
||||
GDScriptTextDocument();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,26 +35,25 @@
|
|||
#include "gdscript_language_protocol.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "editor/doc/doc_tools.h"
|
||||
#include "editor/doc/editor_help.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/file_system/editor_file_system.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "scene/resources/packed_scene.h"
|
||||
|
||||
void GDScriptWorkspace::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("apply_new_signal", "obj", "function", "args"), &GDScriptWorkspace::apply_new_signal);
|
||||
ClassDB::bind_method(D_METHOD("apply_new_signal"), &GDScriptWorkspace::apply_new_signal);
|
||||
ClassDB::bind_method(D_METHOD("get_file_path", "uri"), &GDScriptWorkspace::get_file_path);
|
||||
ClassDB::bind_method(D_METHOD("get_file_uri", "path"), &GDScriptWorkspace::get_file_uri);
|
||||
ClassDB::bind_method(D_METHOD("publish_diagnostics", "path"), &GDScriptWorkspace::publish_diagnostics);
|
||||
ClassDB::bind_method(D_METHOD("generate_script_api", "path"), &GDScriptWorkspace::generate_script_api);
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
ClassDB::bind_method(D_METHOD("didDeleteFiles", "params"), &GDScriptWorkspace::didDeleteFiles);
|
||||
ClassDB::bind_method(D_METHOD("didDeleteFiles"), &GDScriptWorkspace::didDeleteFiles);
|
||||
ClassDB::bind_method(D_METHOD("parse_script", "path", "content"), &GDScriptWorkspace::parse_script);
|
||||
ClassDB::bind_method(D_METHOD("parse_local_script", "path"), &GDScriptWorkspace::parse_local_script);
|
||||
ClassDB::bind_method(D_METHOD("publish_diagnostics", "path"), &GDScriptWorkspace::publish_diagnostics);
|
||||
ClassDB::bind_method(D_METHOD("parse_local_script", "path"), &GDScriptWorkspace::parse_script);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -593,6 +592,51 @@ void GDScriptWorkspace::publish_diagnostics(const String &p_path) {
|
|||
GDScriptLanguageProtocol::get_singleton()->notify_client("textDocument/publishDiagnostics", params);
|
||||
}
|
||||
|
||||
void GDScriptWorkspace::_get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners) {
|
||||
if (!efsd) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < efsd->get_subdir_count(); i++) {
|
||||
_get_owners(efsd->get_subdir(i), p_path, owners);
|
||||
}
|
||||
|
||||
for (int i = 0; i < efsd->get_file_count(); i++) {
|
||||
Vector<String> deps = efsd->get_file_deps(i);
|
||||
bool found = false;
|
||||
for (int j = 0; j < deps.size(); j++) {
|
||||
if (deps[j] == p_path) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
owners.push_back(efsd->get_file_path(i));
|
||||
}
|
||||
}
|
||||
|
||||
Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) {
|
||||
Node *owner_scene_node = nullptr;
|
||||
List<String> owners;
|
||||
|
||||
_get_owners(EditorFileSystem::get_singleton()->get_filesystem(), p_path, owners);
|
||||
|
||||
for (const String &owner : owners) {
|
||||
NodePath owner_path = owner;
|
||||
Ref<Resource> owner_res = ResourceLoader::load(String(owner_path));
|
||||
if (Object::cast_to<PackedScene>(owner_res.ptr())) {
|
||||
Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res));
|
||||
owner_scene_node = owner_packed_scene->instantiate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return owner_scene_node;
|
||||
}
|
||||
|
||||
void GDScriptWorkspace::completion(const LSP::CompletionParams &p_params, List<ScriptLanguage::CodeCompletionOption> *r_options) {
|
||||
String path = get_file_path(p_params.textDocument.uri);
|
||||
String call_hint;
|
||||
|
|
@ -600,7 +644,7 @@ void GDScriptWorkspace::completion(const LSP::CompletionParams &p_params, List<S
|
|||
|
||||
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(path);
|
||||
if (parser) {
|
||||
Node *owner_scene_node = GDScriptLanguageProtocol::get_singleton()->get_scene_cache()->get(path);
|
||||
Node *owner_scene_node = _get_owner_scene_node(path);
|
||||
|
||||
Array stack;
|
||||
Node *current = nullptr;
|
||||
|
|
@ -626,6 +670,9 @@ void GDScriptWorkspace::completion(const LSP::CompletionParams &p_params, List<S
|
|||
|
||||
String code = parser->get_text_for_completion(p_params.position);
|
||||
GDScriptLanguage::get_singleton()->complete_code(code, path, current, r_options, forced, call_hint);
|
||||
if (owner_scene_node) {
|
||||
memdelete(owner_scene_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,18 +30,22 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "gdscript_extend_parser.h"
|
||||
#include "godot_lsp.h"
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/variant/variant.h"
|
||||
#include "editor/file_system/editor_file_system.h"
|
||||
|
||||
class GDScriptWorkspace : public RefCounted {
|
||||
GDCLASS(GDScriptWorkspace, RefCounted);
|
||||
|
||||
private:
|
||||
void _get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners);
|
||||
Node *_get_owner_scene_node(String p_path);
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void didDeleteFiles(const Dictionary &p_params) {}
|
||||
void didDeleteFiles() {}
|
||||
Error parse_script(const String &p_path, const String &p_content) {
|
||||
WARN_DEPRECATED;
|
||||
return Error::FAILED;
|
||||
|
|
|
|||
|
|
@ -34,15 +34,6 @@
|
|||
#include "core/object/class_db.h"
|
||||
#include "core/templates/list.h"
|
||||
|
||||
// Enable additional LSP related logging.
|
||||
//#define DEBUG_LSP
|
||||
|
||||
#ifdef DEBUG_LSP
|
||||
#define LOG_LSP(...) print_line("[ LSP -", __FILE__, ":", __LINE__, "-", __func__, "] -", ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_LSP(...)
|
||||
#endif
|
||||
|
||||
namespace LSP {
|
||||
|
||||
typedef String DocumentUri;
|
||||
|
|
@ -1077,12 +1068,8 @@ struct CompletionItem {
|
|||
dict["insertText"] = insertText;
|
||||
}
|
||||
if (resolved) {
|
||||
if (!detail.is_empty()) {
|
||||
dict["detail"] = detail;
|
||||
}
|
||||
if (!documentation.value.is_empty()) {
|
||||
dict["documentation"] = documentation.to_json();
|
||||
}
|
||||
dict["detail"] = detail;
|
||||
dict["documentation"] = documentation.to_json();
|
||||
dict["deprecated"] = deprecated;
|
||||
dict["preselect"] = preselect;
|
||||
if (!sortText.is_empty()) {
|
||||
|
|
@ -1298,6 +1285,48 @@ struct DocumentSymbol {
|
|||
}
|
||||
return markdown;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ CompletionItem make_completion_item(bool resolved = false) const {
|
||||
LSP::CompletionItem item;
|
||||
item.label = name;
|
||||
|
||||
if (resolved) {
|
||||
item.documentation = render();
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case LSP::SymbolKind::Enum:
|
||||
item.kind = LSP::CompletionItemKind::Enum;
|
||||
break;
|
||||
case LSP::SymbolKind::Class:
|
||||
item.kind = LSP::CompletionItemKind::Class;
|
||||
break;
|
||||
case LSP::SymbolKind::Property:
|
||||
item.kind = LSP::CompletionItemKind::Property;
|
||||
break;
|
||||
case LSP::SymbolKind::Method:
|
||||
case LSP::SymbolKind::Function:
|
||||
item.kind = LSP::CompletionItemKind::Method;
|
||||
break;
|
||||
case LSP::SymbolKind::Event:
|
||||
item.kind = LSP::CompletionItemKind::Event;
|
||||
break;
|
||||
case LSP::SymbolKind::Constant:
|
||||
item.kind = LSP::CompletionItemKind::Constant;
|
||||
break;
|
||||
case LSP::SymbolKind::Variable:
|
||||
item.kind = LSP::CompletionItemKind::Variable;
|
||||
break;
|
||||
case LSP::SymbolKind::File:
|
||||
item.kind = LSP::CompletionItemKind::File;
|
||||
break;
|
||||
default:
|
||||
item.kind = LSP::CompletionItemKind::Text;
|
||||
break;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
struct ApplyWorkspaceEditParams {
|
||||
|
|
@ -1737,7 +1766,7 @@ struct ServerCapabilities {
|
|||
/**
|
||||
* The server provides document highlight support.
|
||||
*/
|
||||
bool documentHighlightProvider = true;
|
||||
bool documentHighlightProvider = false;
|
||||
|
||||
/**
|
||||
* The server provides document symbol support.
|
||||
|
|
@ -2094,26 +2123,4 @@ static String marked_documentation(const String &p_bbcode) {
|
|||
}
|
||||
return markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* A document highlight is a range inside a text document which deserves
|
||||
* special attention. Usually a document highlight is visualized by changing
|
||||
* the background color of its range.
|
||||
*/
|
||||
struct DocumentHighlight {
|
||||
/**
|
||||
* The range this highlight applies to.
|
||||
*/
|
||||
Range range;
|
||||
|
||||
_FORCE_INLINE_ Dictionary to_json() const {
|
||||
Dictionary dict;
|
||||
dict["range"] = range.to_json();
|
||||
return dict;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void load(const Dictionary &p_params) {
|
||||
range.load(p_params["range"]);
|
||||
}
|
||||
};
|
||||
} // namespace LSP
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue