Merge branch 'refactor-network-string' of github.com:supertuxkart/stk-code into refactor-network-string
This commit is contained in:
commit
68e394702b
30
data/gui/ghost_replay_info_dialog.stkgui
Normal file
30
data/gui/ghost_replay_info_dialog.stkgui
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stkgui>
|
||||
<div x="5%" y="5%" width="90%" height="90%" layout="vertical-row">
|
||||
<div x="5%" y="0%" width="90%" proportion="6" layout="horizontal-row">
|
||||
<div width="40%" height="100%" layout="vertical-row">
|
||||
<icon id="icon" align="center" proportion="8" width="100%" icon="gui/loading.png" />
|
||||
<spacer proportion="1" />
|
||||
</div>
|
||||
<spacer proportion="1" />
|
||||
<div width="60%" height="50%" layout="vertical-row">
|
||||
<label id="name" width="100%" text_align="left"/>
|
||||
<spacer height="10"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div width="80%" proportion="5" align="center">
|
||||
<buttonbar id="actions" x="0" y="0" height="100%" width="100%" align="center">
|
||||
<icon-button id="start" width="128" height="128"
|
||||
icon="gui/green_check.png"
|
||||
I18N="Ghost replay info screen action" text="Start Race" />
|
||||
<icon-button id="remove" width="128" height="128"
|
||||
icon="gui/remove.png"
|
||||
I18N="Ghost replay info action" text="Remove" />
|
||||
<icon-button id="back" width="128" height="128"
|
||||
icon="gui/back.png"
|
||||
I18N="Ghost replay info action" text="Back" />
|
||||
</buttonbar>
|
||||
</div>
|
||||
</div>
|
||||
</stkgui>
|
15
data/gui/ghost_replay_selection.stkgui
Normal file
15
data/gui/ghost_replay_selection.stkgui
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stkgui>
|
||||
<div x="0%" y="1%" width="100%" height="98%" layout="vertical-row" >
|
||||
|
||||
<div x="0" y="0" width="100%" layout="horizontal-row" height="8%">
|
||||
<icon-button id="back" height="100%" icon="gui/back.png"/>
|
||||
<header text_align="center" proportion="1" text="Ghost Replay Selection" align="center"/>
|
||||
<icon-button id="reload" height="90%" icon="gui/restart.png"/>
|
||||
</div>
|
||||
|
||||
<box proportion="1" width="98%" align="center" layout="vertical-row" padding="6">
|
||||
<list id="replay_list" x="0" y="0" width="100%" height="100%"/>
|
||||
</box>
|
||||
</div>
|
||||
</stkgui>
|
Binary file not shown.
BIN
data/gui/mode_ghost.png
Normal file
BIN
data/gui/mode_ghost.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stkgui>
|
||||
<div x="0" y="0" width="100%" height="fit" layout="vertical-row">
|
||||
<button id="user-id" width="20%" height="fit" align="right"/>
|
||||
</div>
|
||||
|
||||
<div x="2%" y="2%" width="96%" height="96%" layout="vertical-row" >
|
||||
|
||||
<header text_align="center" width="80%" align="center" I18N="In the online multiplayer screen" text="Online Multiplayer"/>
|
||||
|
||||
<spacer height="5%" width="25"/>
|
||||
<box width="100%" height="38%" padding="10" layout="vertical-row">
|
||||
<bright width="100%" text="Local Networking" align="center" text_align="left" />
|
||||
|
||||
<buttonbar id="lan" proportion="2" width="90%" align="center">
|
||||
<icon-button id="find_lan_server" width="128" height="128"
|
||||
icon="gui/online/menu_find_server.png" focus_icon="gui/online/menu_find_server_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Find Server"/>
|
||||
<icon-button id="create_lan_server" width="128" height="128"
|
||||
icon="gui/online/menu_create_server.png" focus_icon="gui/online/menu_create_server_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Create Server"/>
|
||||
<icon-button id="manage_user" width="128" height="128"
|
||||
icon="gui/options_players.png"
|
||||
I18N="In the online multiplayer screen" text="Users"/>
|
||||
</buttonbar>
|
||||
</box>
|
||||
|
||||
<spacer height="5%" width="25"/>
|
||||
|
||||
<box width="100%" height="38%" padding="10" layout="vertical-row">
|
||||
<bright width="100%" text="Global Networking" align="center" text_align="left" />
|
||||
|
||||
<buttonbar id="menu_top_row" proportion="2" width="90%" align="center">
|
||||
<icon-button id="find_wan_server" width="128" height="128"
|
||||
icon="gui/online/menu_find_server.png" focus_icon="gui/online/menu_find_server_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Find Server"/>
|
||||
<icon-button id="create_wan_server" width="128" height="128"
|
||||
icon="gui/online/menu_create_server.png" focus_icon="gui/online/menu_create_server_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Create Server"/>
|
||||
<icon-button id="quick_wan_play" width="128" height="128"
|
||||
icon="gui/online/menu_quick_play.png" focus_icon="gui/online/menu_quick_play_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Quick Play"/>
|
||||
</buttonbar>
|
||||
</box>
|
||||
|
||||
<bottombar x="2%" width="96%" height="10%" layout="horizontal-row">
|
||||
<label text_align="left" align="center" height="100%" id="online_status" proportion="1" text=""/>
|
||||
|
||||
<spacer width="10" height="10" />
|
||||
|
||||
<buttonbar id="menu_bottomrow" x="0" y="0" width="12%" height="100%" align="center">
|
||||
<icon-button id="profile" width="64" height="64" icon="gui/green_check.png" extend_label="50"
|
||||
I18N="In the online multiplayer screen" text="Profile" label_location="hover"/>
|
||||
<icon-button id="sign_out" width="64" height="64" icon="gui/main_quit.png" extend_label="70"
|
||||
I18N="In the online multiplayer screen" text="Log Out" label_location="hover"/>
|
||||
</buttonbar>
|
||||
|
||||
</bottombar>
|
||||
|
||||
</div>
|
||||
|
||||
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
|
||||
</stkgui>
|
@ -9,6 +9,7 @@
|
||||
<spacer height="25" width="10"/>
|
||||
|
||||
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
|
||||
<icon-button id="tab_servers" width="128" height="128" icon="gui/main_network.png"/>
|
||||
<icon-button id="tab_achievements" width="128" height="128" icon="gui/gp_copy.png"
|
||||
I18N="Section in the profile screen" text="Achievements"/>
|
||||
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png"/>
|
||||
|
@ -9,6 +9,7 @@
|
||||
<spacer height="25" width="10"/>
|
||||
|
||||
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
|
||||
<icon-button id="tab_servers" width="128" height="128" icon="gui/main_network.png"/>
|
||||
<icon-button id="tab_achievements" width="128" height="128" icon="gui/gp_copy.png"/>
|
||||
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png"
|
||||
I18N="Section in the profile screen" text="Friends"/>
|
||||
|
61
data/gui/online/profile_servers.stkgui
Normal file
61
data/gui/online/profile_servers.stkgui
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stkgui>
|
||||
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
|
||||
|
||||
<div x="1%" y="1%" width="98%" height="98%" layout="vertical-row" >
|
||||
<header id="title" text_align="center" width="80%" align="center" text="..."/>
|
||||
|
||||
<spacer height="25" width="10"/>
|
||||
|
||||
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
|
||||
<icon-button id="tab_servers" width="128" height="128" icon="gui/main_network.png" I18N="Section in the profile screen" text="Servers"/>
|
||||
<icon-button id="tab_achievements" width="128" height="128" icon="gui/gp_copy.png"/>
|
||||
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png" />
|
||||
<icon-button id="tab_settings" width="128" height="128" icon="gui/main_options.png" />
|
||||
</tabs>
|
||||
|
||||
<box proportion="1" width="100%" layout="vertical-row">
|
||||
<div x="1%" y="2%" width="98%" height="96%" layout="vertical-row" >
|
||||
|
||||
<spacer height="5%" width="25"/>
|
||||
|
||||
<box width="100%" proportion="1" padding="10" layout="vertical-row">
|
||||
<bright width="100%" text="Local Networking" align="center" text_align="left" />
|
||||
|
||||
<buttonbar id="lan" proportion="2" width="90%" align="center">
|
||||
<icon-button id="find_lan_server" width="128" height="128"
|
||||
icon="gui/online/menu_find_server.png" focus_icon="gui/online/menu_find_server_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Find Server"/>
|
||||
<icon-button id="create_lan_server" width="128" height="128"
|
||||
icon="gui/online/menu_create_server.png" focus_icon="gui/online/menu_create_server_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Create Server"/>
|
||||
<!--
|
||||
<icon-button id="manage_user" width="128" height="128"
|
||||
icon="gui/options_players.png"
|
||||
I18N="In the online multiplayer screen" text="Users"/>
|
||||
-->
|
||||
</buttonbar>
|
||||
</box>
|
||||
|
||||
<spacer height="5%" width="25"/>
|
||||
|
||||
<box width="100%" proportion="1" padding="10" layout="vertical-row">
|
||||
<bright width="100%" text="Global Networking" align="center" text_align="left" />
|
||||
|
||||
<buttonbar id="wan" proportion="2" width="90%" align="center">
|
||||
<icon-button id="find_wan_server" width="128" height="128"
|
||||
icon="gui/online/menu_find_server.png" focus_icon="gui/online/menu_find_server_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Find Server"/>
|
||||
<icon-button id="create_wan_server" width="128" height="128"
|
||||
icon="gui/online/menu_create_server.png" focus_icon="gui/online/menu_create_server_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Create Server"/>
|
||||
<icon-button id="quick_wan_play" width="128" height="128"
|
||||
icon="gui/online/menu_quick_play.png" focus_icon="gui/online/menu_quick_play_hover.png"
|
||||
I18N="In the online multiplayer screen" text="Quick Play"/>
|
||||
</buttonbar>
|
||||
</box>
|
||||
|
||||
</div>
|
||||
</box>
|
||||
</div>
|
||||
</stkgui>
|
@ -8,6 +8,7 @@
|
||||
<spacer height="25" width="10"/>
|
||||
|
||||
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
|
||||
<icon-button id="tab_servers" width="128" height="128" icon="gui/main_network.png"/>
|
||||
<icon-button id="tab_achievements" width="128" height="128" icon="gui/gp_copy.png"/>
|
||||
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png" />
|
||||
<icon-button id="tab_settings" width="128" height="128" icon="gui/main_options.png"
|
||||
|
11
data/gui/online/waiting_for_others.stkgui
Normal file
11
data/gui/online/waiting_for_others.stkgui
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stkgui>
|
||||
<div x="2%" y="5%" width="96%" height="90%" layout="vertical-row" >
|
||||
|
||||
<header id="title" width="96%" height="fit" text_align="center" I18N="Networking screen" text="Waiting for the others..."/>
|
||||
|
||||
<spacer height="40" width="50"/>
|
||||
|
||||
Waiting...
|
||||
</div>
|
||||
</stkgui>
|
@ -3,9 +3,9 @@
|
||||
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
|
||||
|
||||
<div x="2%" y="2%" width="96%" height="96%" layout="vertical-row">
|
||||
<header id="name" height="5%" width="80%" align="center" text_align="center"/>
|
||||
<header id="name" height="7%" width="80%" align="center" text_align="center"/>
|
||||
|
||||
<spacer width="1" height="5%"/>
|
||||
<spacer width="1" height="1%"/>
|
||||
|
||||
<box width="100%" height="40%" padding="10" layout="horizontal-row">
|
||||
<!-- Left pane -->
|
||||
@ -49,8 +49,8 @@
|
||||
</div>
|
||||
|
||||
</box>
|
||||
<spacer width="1" height="5%"/>
|
||||
<box width="100%" height="25%" padding="15" layout="vertical-row">
|
||||
<spacer width="1" height="1%"/>
|
||||
<box width="100%" height="33%" padding="15" layout="vertical-row">
|
||||
<div width="100%" height="fit" layout="horizontal-row" >
|
||||
<label id="lap-text" proportion="1" I18N="In the track info screen" text="Number of laps" text_align="right"/>
|
||||
<spacer width="40"/>
|
||||
@ -78,9 +78,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<spacer width="1" height="2%"/>
|
||||
<div width="100%" height="fit" layout="horizontal-row" >
|
||||
<label id="record-race-text" proportion="1" I18N="In the track info screen" text="Record the race for ghost replay" text_align="right"/>
|
||||
<spacer width="40"/>
|
||||
<div proportion="1" height="fit" layout="horizontal-row">
|
||||
<div width="50%" height="fit" text-align="center" layout="vertical-row" >
|
||||
<checkbox id="record" align="center"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<spacer width="1" height="1%"/>
|
||||
</box>
|
||||
<spacer width="1" height="5%"/>
|
||||
<spacer width="1" height="1%"/>
|
||||
<buttonbar id="buttons" height="15%" width="100%" align="center">
|
||||
<icon-button id="start" width="64" height="64" icon="gui/green_check.png"
|
||||
I18N="In the track info screen" text="Start Race"/>
|
||||
|
@ -81,6 +81,10 @@ when the border that intersect at this corner are enabled.
|
||||
left_border="128" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
||||
<element type="generic-message" image="forest/generic.png"
|
||||
left_border="128" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
||||
<element type="button" state="neutral" image="forest/glassbutton.png"
|
||||
left_border="13" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
@ -80,6 +80,10 @@ when the border that intersect at this corner are enabled.
|
||||
left_border="128" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
||||
<element type="generic-message" image="ocean/generic.png"
|
||||
left_border="128" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
||||
<element type="button" state="neutral" image="ocean/glassbutton.png"
|
||||
left_border="13" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
@ -80,6 +80,10 @@ when the border that intersect at this corner are enabled.
|
||||
left_border="128" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
||||
<element type="generic-message" image="peach/generic.png"
|
||||
left_border="128" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
||||
<element type="button" state="neutral" image="peach/glassbutton.png"
|
||||
left_border="13" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
@ -81,6 +81,10 @@ when the border that intersect at this corner are enabled.
|
||||
left_border="128" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
||||
<element type="generic-message" image="ruby/generic.png"
|
||||
left_border="128" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
||||
<element type="button" state="neutral" image="ruby/glassbutton.png"
|
||||
left_border="13" right_border="13" top_border="13" bottom_border="13"
|
||||
preserve_h_aspect_ratios="true" hborder_out_portion="0" vborder_out_portion="0"/>
|
||||
|
BIN
data/skins/forest/generic.png
Normal file
BIN
data/skins/forest/generic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
data/skins/ocean/generic.png
Normal file
BIN
data/skins/ocean/generic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
data/skins/peach/generic.png
Normal file
BIN
data/skins/peach/generic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
data/skins/ruby/generic.png
Normal file
BIN
data/skins/ruby/generic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
@ -58,8 +58,8 @@ BEGIN_AS_NAMESPACE
|
||||
|
||||
// AngelScript version
|
||||
|
||||
#define ANGELSCRIPT_VERSION 23000
|
||||
#define ANGELSCRIPT_VERSION_STRING "2.30.0 WIP"
|
||||
#define ANGELSCRIPT_VERSION 23002
|
||||
#define ANGELSCRIPT_VERSION_STRING "2.30.2"
|
||||
|
||||
// Data types
|
||||
|
||||
@ -543,7 +543,7 @@ struct asSMessageInfo
|
||||
extern "C"
|
||||
{
|
||||
// Engine
|
||||
AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version);
|
||||
AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version = ANGELSCRIPT_VERSION);
|
||||
AS_API const char *asGetLibraryVersion();
|
||||
AS_API const char *asGetLibraryOptions();
|
||||
|
||||
@ -585,20 +585,20 @@ template<typename T>
|
||||
asUINT asGetTypeTraits()
|
||||
{
|
||||
#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5)
|
||||
// MSVC & XCode/Clang, and gnuc 5+
|
||||
// MSVC, XCode/Clang, and gnuc 5+
|
||||
// C++11 compliant code
|
||||
bool hasConstructor = std::is_default_constructible<T>::value && !std::is_trivially_default_constructible<T>::value;
|
||||
bool hasDestructor = std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value;
|
||||
bool hasAssignmentOperator = std::is_copy_assignable<T>::value && !std::is_trivially_copy_assignable<T>::value;
|
||||
bool hasCopyConstructor = std::is_copy_constructible<T>::value && !std::is_trivially_copy_constructible<T>::value;
|
||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
||||
// gnuc 4.8+
|
||||
// gnuc is using a mix of C++11 standard and pre-standard templates
|
||||
// gnuc 4.8 is using a mix of C++11 standard and pre-standard templates
|
||||
bool hasConstructor = std::is_default_constructible<T>::value && !std::has_trivial_default_constructor<T>::value;
|
||||
bool hasDestructor = std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value;
|
||||
bool hasAssignmentOperator = std::is_copy_assignable<T>::value && !std::has_trivial_copy_assign<T>::value;
|
||||
bool hasCopyConstructor = std::is_copy_constructible<T>::value && !std::has_trivial_copy_constructor<T>::value;
|
||||
#else
|
||||
// All other compilers and versions are assumed to use non C++11 compliant code until proven otherwise
|
||||
// Not fully C++11 compliant. The has_trivial checks were used while the standard was still
|
||||
// being elaborated, but were then removed in favor of the above is_trivially checks
|
||||
// http://stackoverflow.com/questions/12702103/writing-code-that-works-when-has-trivial-destructor-is-defined-instead-of-is
|
||||
@ -1556,8 +1556,8 @@ enum asEBCInstr
|
||||
asBC_POWdi = 197,
|
||||
asBC_POWi64 = 198,
|
||||
asBC_POWu64 = 199,
|
||||
|
||||
asBC_MAXBYTECODE = 200,
|
||||
asBC_Thiscall1 = 200,
|
||||
asBC_MAXBYTECODE = 201,
|
||||
|
||||
// Temporary tokens. Can't be output to the final program
|
||||
asBC_VarDecl = 251,
|
||||
@ -1851,8 +1851,8 @@ const asSBCInfo asBCInfo[256] =
|
||||
asBCINFO(POWdi, wW_rW_rW_ARG, 0),
|
||||
asBCINFO(POWi64, wW_rW_rW_ARG, 0),
|
||||
asBCINFO(POWu64, wW_rW_rW_ARG, 0),
|
||||
asBCINFO(Thiscall1, DW_ARG, -AS_PTR_SIZE-1),
|
||||
|
||||
asBCINFO_DUMMY(200),
|
||||
asBCINFO_DUMMY(201),
|
||||
asBCINFO_DUMMY(202),
|
||||
asBCINFO_DUMMY(203),
|
||||
|
@ -14,11 +14,15 @@ if(APPLE)
|
||||
option(BUILD_FRAMEWORK "Build Framework bundle for OSX" OFF)
|
||||
endif()
|
||||
|
||||
set(ANGELSCRIPT_VERSION_MAJOR 2)
|
||||
set(ANGELSCRIPT_VERSION_MINOR 30)
|
||||
set(ANGELSCRIPT_VERSION_PATCH 0)
|
||||
file(READ ../../include/angelscript.h ANGELSCRIPT_H)
|
||||
string(REGEX MATCH "#define ANGELSCRIPT_VERSION_STRING \"([0-9]*).([0-9]*).([0-9]*)" ANGELSCRIPT_VERSION_REGEX ${ANGELSCRIPT_H})
|
||||
set(ANGELSCRIPT_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(ANGELSCRIPT_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
set(ANGELSCRIPT_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
set(PROJECT_VERSION ${ANGELSCRIPT_VERSION_MAJOR}.${ANGELSCRIPT_VERSION_MINOR}.${ANGELSCRIPT_VERSION_PATCH})
|
||||
|
||||
message(STATUS "Configuring angelscript ${PROJECT_VERSION}")
|
||||
|
||||
find_package(Threads)
|
||||
|
||||
set(ANGELSCRIPT_HEADERS
|
||||
@ -102,12 +106,13 @@ if(MSVC AND CMAKE_CL_64)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm")
|
||||
enable_language(ASM)
|
||||
if(CMAKE_ASM_COMPILER_WORKS)
|
||||
set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_arm.cpp ../../source/as_callfunc_arm_gcc.S)
|
||||
set_property(SOURCE ../../source/as_callfunc_arm_gcc.S APPEND PROPERTY COMPILE_FLAGS " -Wa,-mimplicit-it=always")
|
||||
else()
|
||||
message(FATAL ERROR "Android target requires a working assembler")
|
||||
message(FATAL ERROR "ARM target requires a working assembler")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -156,4 +161,5 @@ endif()
|
||||
|
||||
#set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../../bin)
|
||||
|
||||
#add_subdirectory(../../../samples/game/projects/cmake/ ./game)
|
||||
|
||||
|
@ -363,9 +363,35 @@ int asCBuilder::CompileGlobalVar(const char *sectionName, const char *code, int
|
||||
|
||||
CompileGlobalVariables();
|
||||
|
||||
// It is possible that the global variable initialization included anonymous functions that must be compiled too
|
||||
for( asUINT n = 0; n < functions.GetLength(); n++ )
|
||||
{
|
||||
asCCompiler compiler(engine);
|
||||
asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
|
||||
int r = compiler.CompileFunction(this, functions[n]->script, func->parameterNames, functions[n]->node, func, 0);
|
||||
if( r < 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
if( numWarnings > 0 && engine->ep.compilerWarnings == 2 )
|
||||
WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0);
|
||||
|
||||
// None of the functions should be added to the module if any error occurred,
|
||||
// or it was requested that the functions wouldn't be added to the scope
|
||||
if( numErrors > 0 )
|
||||
{
|
||||
for( asUINT n = 0; n < functions.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
|
||||
if( module->globalFunctions.GetIndex(func) >= 0 )
|
||||
{
|
||||
module->globalFunctions.Erase(module->globalFunctions.GetIndex(func));
|
||||
module->scriptFunctions.RemoveValue(func);
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( numErrors > 0 )
|
||||
{
|
||||
// Remove the variable from the module, if it was registered
|
||||
@ -549,22 +575,38 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l
|
||||
funcDesc->paramNames = func->parameterNames;
|
||||
funcDesc->isExistingShared = false;
|
||||
|
||||
asCCompiler compiler(engine);
|
||||
compiler.CompileFunction(this, functions[0]->script, func->parameterNames, functions[0]->node, func, 0);
|
||||
// This must be done in a loop, as it is possible that additional functions get declared as lambda's in the code
|
||||
for( asUINT n = 0; n < functions.GetLength(); n++ )
|
||||
{
|
||||
asCCompiler compiler(engine);
|
||||
asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
|
||||
int r = compiler.CompileFunction(this, functions[n]->script, func->parameterNames, functions[n]->node, func, 0);
|
||||
if( r < 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
if( numWarnings > 0 && engine->ep.compilerWarnings == 2 )
|
||||
WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0);
|
||||
|
||||
// None of the functions should be added to the module if any error occurred,
|
||||
// or it was requested that the functions wouldn't be added to the scope
|
||||
if( !(compileFlags & asCOMP_ADD_TO_MODULE) || numErrors > 0 )
|
||||
{
|
||||
for( asUINT n = 0; n < functions.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
|
||||
if( module->globalFunctions.GetIndex(func) >= 0 )
|
||||
{
|
||||
module->globalFunctions.Erase(module->globalFunctions.GetIndex(func));
|
||||
module->scriptFunctions.RemoveValue(func);
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( numErrors > 0 )
|
||||
{
|
||||
// If the function was added to the module then remove it again
|
||||
if( compileFlags & asCOMP_ADD_TO_MODULE )
|
||||
{
|
||||
module->globalFunctions.Erase(module->globalFunctions.GetIndex(func));
|
||||
module->scriptFunctions.RemoveValue(func);
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
|
||||
// Release the function pointer that would otherwise be returned if no errors occured
|
||||
func->ReleaseInternal();
|
||||
|
||||
return asERROR;
|
||||
@ -965,15 +1007,20 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam
|
||||
if( r < 0 )
|
||||
return asINVALID_DECLARATION;
|
||||
|
||||
// Get data type and property name
|
||||
// Get data type
|
||||
asCScriptNode *dataType = parser.GetScriptNode()->firstChild;
|
||||
|
||||
asCScriptNode *nameNode = dataType->next;
|
||||
// Check if the property is declared 'by reference'
|
||||
bool isReference = (dataType->next->tokenType == ttAmp);
|
||||
|
||||
// Get the name of the property
|
||||
asCScriptNode *nameNode = isReference ? dataType->next->next : dataType->next;
|
||||
|
||||
// If an object property is registered, then use the
|
||||
// object's namespace, otherwise use the specified namespace
|
||||
type = CreateDataTypeFromNode(dataType, &source, dt ? dt->GetObjectType()->nameSpace : ns);
|
||||
name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength);
|
||||
type.MakeReference(isReference);
|
||||
|
||||
// Validate that the type really can be a registered property
|
||||
// We cannot use CanBeInstantiated, as it is allowed to register
|
||||
@ -1458,9 +1505,9 @@ sMixinClass *asCBuilder::GetMixinClass(const char *name, asSNameSpace *ns)
|
||||
|
||||
int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Allow funcdefs to be explicitly declared as 'shared'. In this case
|
||||
// an error should be given if any of the arguments/return type is not
|
||||
// shared.
|
||||
// TODO: redesign: Allow funcdefs to be explicitly declared as 'shared'. In this case
|
||||
// an error should be given if any of the arguments/return type is not
|
||||
// shared.
|
||||
|
||||
// Find the name
|
||||
asASSERT( node->firstChild->nodeType == snDataType );
|
||||
@ -1516,6 +1563,7 @@ void asCBuilder::CompleteFuncDef(sFuncDef *funcDef)
|
||||
asCScriptFunction *func = module->funcDefs[funcDef->idx];
|
||||
asASSERT( func );
|
||||
|
||||
// TODO: It should be possible to declare funcdef as shared. In this case a compiler error will be given if any of the types it uses are not shared
|
||||
GetParsedFunctionDetails(funcDef->node, funcDef->script, 0, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared, func->nameSpace);
|
||||
|
||||
// There should not be any defaultArgs, but if there are any we need to delete them to avoid leaks
|
||||
@ -1523,27 +1571,47 @@ void asCBuilder::CompleteFuncDef(sFuncDef *funcDef)
|
||||
if( defaultArgs[n] )
|
||||
asDELETE(defaultArgs[n], asCString);
|
||||
|
||||
// TODO: Should we force the use of 'shared' for this check to be done?
|
||||
// Check if there is another identical funcdef from another module and if so reuse that instead
|
||||
for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
|
||||
// All funcdefs are shared, unless one of the parameter types or return type is not shared
|
||||
isShared = true;
|
||||
if( func->returnType.GetObjectType() && !func->returnType.GetObjectType()->IsShared() )
|
||||
isShared = false;
|
||||
if( func->returnType.GetFuncDef() && !func->returnType.GetFuncDef()->IsShared() )
|
||||
isShared = false;
|
||||
for( asUINT n = 0; isShared && n < func->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
if( func->parameterTypes[n].GetObjectType() && !func->parameterTypes[n].GetObjectType()->IsShared() )
|
||||
isShared = false;
|
||||
if( func->parameterTypes[n].GetFuncDef() && !func->parameterTypes[n].GetFuncDef()->IsShared() )
|
||||
isShared = false;
|
||||
}
|
||||
func->isShared = isShared;
|
||||
|
||||
if( f2->name == func->name &&
|
||||
f2->nameSpace == func->nameSpace &&
|
||||
f2->IsSignatureExceptNameEqual(func) )
|
||||
// Check if there is another identical funcdef from another module and if so reuse that instead
|
||||
if( func->isShared )
|
||||
{
|
||||
for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
|
||||
{
|
||||
// Replace our funcdef for the existing one
|
||||
funcDef->idx = f2->id;
|
||||
module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
|
||||
f2->AddRefInternal();
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
if( !f2->isShared )
|
||||
continue;
|
||||
|
||||
func->ReleaseInternal();
|
||||
break;
|
||||
if( f2->name == func->name &&
|
||||
f2->nameSpace == func->nameSpace &&
|
||||
f2->IsSignatureExceptNameEqual(func) )
|
||||
{
|
||||
// Replace our funcdef for the existing one
|
||||
funcDef->idx = f2->id;
|
||||
module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
|
||||
f2->AddRefInternal();
|
||||
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
|
||||
func->ReleaseInternal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2463,7 +2531,7 @@ void asCBuilder::CompileInterfaces()
|
||||
sClassDeclaration *intfDecl = interfaceDeclarations[n];
|
||||
asCObjectType *intfType = intfDecl->objType;
|
||||
|
||||
// TODO: 2.28.1: Is this really at the correct place? Hasn't the vfTableIdx already been set here?
|
||||
// TODO: Is this really at the correct place? Hasn't the vfTableIdx already been set here?
|
||||
// Co-opt the vfTableIdx value in our own methods to indicate the
|
||||
// index the function should have in the table chunk for this interface.
|
||||
for( asUINT d = 0; d < intfType->methods.GetLength(); d++ )
|
||||
@ -4124,6 +4192,34 @@ int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCod
|
||||
return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared);
|
||||
}
|
||||
|
||||
asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns)
|
||||
{
|
||||
// Get the parameter names from the node
|
||||
asCArray<asCString> parameterNames;
|
||||
asCArray<asCString*> defaultArgs;
|
||||
asCScriptNode *args = node->firstChild;
|
||||
while( args && args->nodeType == snIdentifier )
|
||||
{
|
||||
asCString argName;
|
||||
argName.Assign(&file->code[args->tokenPos], args->tokenLength);
|
||||
parameterNames.PushLast(argName);
|
||||
defaultArgs.PushLast(0);
|
||||
args = args->next;
|
||||
}
|
||||
|
||||
// The statement block for the function must be disconnected, as the builder is going to be the owner of it
|
||||
args->DisconnectParent();
|
||||
|
||||
// Get the return and parameter types from the funcDef
|
||||
asCString funcName = name;
|
||||
int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, false, false, false, false, false, false, false, false);
|
||||
if( r < 0 )
|
||||
return 0;
|
||||
|
||||
// Return the function that was just created (but that will be compiled later)
|
||||
return engine->scriptFunctions[functions[functions.GetLength()-1]->funcId];
|
||||
}
|
||||
|
||||
int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray<asCString> ¶meterNames, asCArray<asCDataType> ¶meterTypes, asCArray<asETypeModifiers> &inOutFlags, asCArray<asCString *> &defaultArgs, bool isConstMethod, bool isConstructor, bool isDestructor, bool isPrivate, bool isProtected, bool isOverride, bool isFinal, bool isShared)
|
||||
{
|
||||
// Determine default namespace if not specified
|
||||
@ -4734,11 +4830,15 @@ void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *ob
|
||||
// If searching with a scope informed, then the node and script must also be informed for potential error reporting
|
||||
asASSERT( errNode && script );
|
||||
|
||||
// If the scope contains ::identifier, then use the last identifier as the class name and the rest of is as the namespace
|
||||
// If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace
|
||||
int n = scope.FindLast("::");
|
||||
asCString className = n >= 0 ? scope.SubString(n+2) : scope;
|
||||
asCString nsName = n >= 0 ? scope.SubString(0, n) : "";
|
||||
asSNameSpace *ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script);
|
||||
|
||||
// Check if the namespace actually exist, if not return silently as this cannot be the referring to a base class
|
||||
asSNameSpace *ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script, false);
|
||||
if( ns == 0 )
|
||||
return;
|
||||
|
||||
// Find the base class with the specified scope
|
||||
while( objectType && (objectType->name != className || objectType->nameSpace != ns) )
|
||||
@ -4894,7 +4994,7 @@ asSNameSpace *asCBuilder::GetNameSpaceFromNode(asCScriptNode *node, asCScriptCod
|
||||
return GetNameSpaceByString(scope, implicitNs, node, script);
|
||||
}
|
||||
|
||||
asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script)
|
||||
asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, bool isRequired)
|
||||
{
|
||||
asSNameSpace *ns = implicitNs;
|
||||
if( nsName == "::" )
|
||||
@ -4902,7 +5002,7 @@ asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameS
|
||||
else if( nsName != "" )
|
||||
{
|
||||
ns = engine->FindNameSpace(nsName.AddressOf());
|
||||
if( ns == 0 )
|
||||
if( ns == 0 && isRequired )
|
||||
{
|
||||
asCString msg;
|
||||
msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, nsName.AddressOf());
|
||||
@ -5073,6 +5173,12 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
|
||||
ot = otInstance;
|
||||
}
|
||||
}
|
||||
else if( n && n->next && n->next->nodeType == snDataType )
|
||||
{
|
||||
asCString str;
|
||||
str.Format(TXT_TYPE_s_NOT_TEMPLATE, ot->name.AddressOf());
|
||||
WriteError(str, file, n);
|
||||
}
|
||||
|
||||
// Create object data type
|
||||
if( ot )
|
||||
|
@ -174,7 +174,7 @@ protected:
|
||||
asCString GetCleanExpressionString(asCScriptNode *n, asCScriptCode *file);
|
||||
|
||||
asSNameSpace *GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next);
|
||||
asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script);
|
||||
asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, bool isRequired = true);
|
||||
asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0);
|
||||
|
||||
asCObjectType *GetObjectType(const char *type, asSNameSpace *ns);
|
||||
@ -213,6 +213,7 @@ protected:
|
||||
int RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
int RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns);
|
||||
void CompleteFuncDef(sFuncDef *funcDef);
|
||||
void CompileInterfaces();
|
||||
void CompileClasses(asUINT originalNumTempl);
|
||||
|
@ -1015,6 +1015,21 @@ void asCByteCode::OptimizeLocally(const asCArray<int> &tempVariableOffsets)
|
||||
ChangeFirstDeleteNext(curr, asBC_PSF);
|
||||
instr = GoForward(curr);
|
||||
}
|
||||
// VAR a, GETOBJREF 0 -> PshVPtr a
|
||||
else if( curr->next && curr->next->op == asBC_GETOBJREF && curr->next->wArg[0] == 0 )
|
||||
{
|
||||
ChangeFirstDeleteNext(curr, asBC_PshVPtr);
|
||||
instr = GoForward(curr);
|
||||
}
|
||||
// VAR, PSF, GETREF {PTR_SIZE} -> PSF, PSF
|
||||
if( curr->next && curr->next->op == asBC_PSF &&
|
||||
curr->next->next && curr->next->next->op == asBC_GETREF &&
|
||||
curr->next->next->wArg[0] == AS_PTR_SIZE )
|
||||
{
|
||||
curr->op = asBC_PSF;
|
||||
DeleteInstruction(curr->next->next);
|
||||
instr = GoForward(curr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2220,6 +2235,13 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_FuncPtr:
|
||||
{
|
||||
asCScriptFunction *func = *(asCScriptFunction**)ARG_DW(instr->arg);
|
||||
fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), func->GetDeclaration());
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_PshC4:
|
||||
case asBC_Cast:
|
||||
fprintf(file, " %-8s 0x%x (i:%d, f:%g)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), *((int*) ARG_DW(instr->arg)), *((float*) ARG_DW(instr->arg)));
|
||||
@ -2233,6 +2255,7 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
case asBC_CALLSYS:
|
||||
case asBC_CALLBND:
|
||||
case asBC_CALLINTF:
|
||||
case asBC_Thiscall1:
|
||||
{
|
||||
int funcID = *(int*)ARG_DW(instr->arg);
|
||||
asCString decl = engine->GetFunctionDeclaration(funcID);
|
||||
@ -2268,11 +2291,18 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
{
|
||||
case asBC_OBJTYPE:
|
||||
{
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
|
||||
fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), ot->GetName());
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_FuncPtr:
|
||||
{
|
||||
asCScriptFunction *func = *(asCScriptFunction**)ARG_QW(instr->arg);
|
||||
fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), func->GetDeclaration());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef __GNUC__
|
||||
#ifdef _LP64
|
||||
@ -2288,15 +2318,27 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
|
||||
case asBCTYPE_wW_QW_ARG:
|
||||
case asBCTYPE_rW_QW_ARG:
|
||||
switch( instr->op )
|
||||
{
|
||||
case asBC_RefCpyV:
|
||||
case asBC_FREE:
|
||||
{
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
|
||||
fprintf(file, " %-8s v%d, 0x%x (type:%s)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_QW(instr->arg), ot->GetName());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef __GNUC__
|
||||
#ifdef _LP64
|
||||
fprintf(file, " %-8s v%d, 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
fprintf(file, " %-8s v%d, 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
#else
|
||||
fprintf(file, " %-8s v%d, 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
fprintf(file, " %-8s v%d, 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
#endif
|
||||
#else
|
||||
fprintf(file, " %-8s v%d, 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
fprintf(file, " %-8s v%d, 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case asBCTYPE_DW_DW_ARG:
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -130,6 +130,8 @@ public:
|
||||
int InstrW_W(asEBCInstr bc, int w, int b);
|
||||
int InstrSHORT_DW_DW(asEBCInstr bc, short a, asDWORD b, asDWORD c);
|
||||
|
||||
asCScriptEngine *GetEngine() const { return engine; };
|
||||
|
||||
asCArray<int> lineNumbers;
|
||||
asCArray<int> sectionIdxs;
|
||||
int largestStackUsed;
|
||||
|
@ -130,10 +130,11 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv,
|
||||
internal->callConv = (internalCallConv)(thisCallConv + 2);
|
||||
#endif
|
||||
internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr);
|
||||
#if defined(AS_ARM) && (defined(__GNUC__) || defined(AS_PSVITA))
|
||||
#if (defined(AS_ARM) || defined(AS_MIPS)) && (defined(__GNUC__) || defined(AS_PSVITA))
|
||||
// As the least significant bit in func is used to switch to THUMB mode
|
||||
// on ARM processors, the LSB in the __delta variable is used instead of
|
||||
// the one in __pfn on ARM processors.
|
||||
// MIPS also appear to use the base offset to indicate virtual method.
|
||||
if( (size_t(internal->baseOffset) & 1) )
|
||||
internal->callConv = (internalCallConv)(thisCallConv + 2);
|
||||
#endif
|
||||
@ -577,10 +578,11 @@ int CallSystemFunction(int id, asCContext *context)
|
||||
}
|
||||
|
||||
// Add the base offset for multiple inheritance
|
||||
#if (defined(__GNUC__) && defined(AS_ARM)) || defined(AS_PSVITA)
|
||||
#if (defined(__GNUC__) && (defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA)
|
||||
// On GNUC + ARM the lsb of the offset is used to indicate a virtual function
|
||||
// and the whole offset is thus shifted one bit left to keep the original
|
||||
// offset resolution
|
||||
// MIPS also work like ARM in this regard
|
||||
obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1));
|
||||
#else
|
||||
obj = (void*)(asPWORD(obj) + sysFunc->baseOffset);
|
||||
@ -634,10 +636,11 @@ int CallSystemFunction(int id, asCContext *context)
|
||||
}
|
||||
|
||||
// Add the base offset for multiple inheritance
|
||||
#if (defined(__GNUC__) && defined(AS_ARM)) || defined(AS_PSVITA)
|
||||
#if (defined(__GNUC__) && (defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA)
|
||||
// On GNUC + ARM the lsb of the offset is used to indicate a virtual function
|
||||
// and the whole offset is thus shifted one bit left to keep the original
|
||||
// offset resolution
|
||||
// MIPS also work like ARM in this regard
|
||||
tempPtr = (void*)(asPWORD(tempPtr) + (sysFunc->baseOffset>>1));
|
||||
#else
|
||||
tempPtr = (void*)(asPWORD(tempPtr) + sysFunc->baseOffset);
|
||||
@ -822,7 +825,15 @@ int CallSystemFunction(int id, asCContext *context)
|
||||
if( cleanCount )
|
||||
{
|
||||
args = context->m_regs.stackPointer;
|
||||
if( callConv >= ICC_THISCALL )
|
||||
|
||||
// Skip the hidden argument for the return pointer
|
||||
// TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction
|
||||
if( descr->DoesReturnOnStack() )
|
||||
args += AS_PTR_SIZE;
|
||||
|
||||
// Skip the object pointer on the stack
|
||||
// TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction
|
||||
if( callConv >= ICC_THISCALL && sysFunc->objForThiscall == 0 )
|
||||
args += AS_PTR_SIZE;
|
||||
|
||||
asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -39,11 +39,13 @@
|
||||
The assembler routines for Linux were written by Carlos Luna in December 2012
|
||||
*/
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#if defined(__arm__) || defined(__ARM__) || defined(I3D_ARCH_ARM)
|
||||
|
||||
#if !defined(__linux__) || defined(__ANDROID__) || defined(ANDROID) || defined(__SOFTFP__)
|
||||
|
||||
/* iOS, Android, and Marmalade goes here */
|
||||
/* iOS, Android, Marmalade, and Linux with soft-float ABI goes here */
|
||||
|
||||
.global armFunc
|
||||
.global armFuncR0
|
||||
@ -85,7 +87,12 @@ stackargsloop:
|
||||
bne stackargsloop
|
||||
mov sp, r12
|
||||
nomoreargs:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
@ -133,7 +140,12 @@ stackargslooparmFuncObjLast:
|
||||
bne stackargslooparmFuncObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncObjLast:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
@ -180,7 +192,12 @@ stackargslooparmFuncR0ObjLast:
|
||||
bne stackargslooparmFuncR0ObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
@ -218,7 +235,12 @@ stackargslooparmFuncR0:
|
||||
bne stackargslooparmFuncR0
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
@ -255,14 +277,19 @@ stackargslooparmFuncR0R1:
|
||||
bne stackargslooparmFuncR0R1
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0R1:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
#elif defined(__linux__) && !defined(__SOFTFP__)
|
||||
|
||||
/* The Linux code goes here */
|
||||
/* The Linux with hard-float ABI code goes here */
|
||||
|
||||
|
||||
/* These codes are suitable for armeabi + vfp / armeabihf */
|
||||
@ -340,7 +367,7 @@ stackargsloop:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargs:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
@ -427,8 +454,8 @@ stackargslooparmFuncObjLast:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncObjLast:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
@ -521,8 +548,8 @@ stackargslooparmFuncR0ObjLast:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
@ -597,8 +624,8 @@ stackargslooparmFuncR0:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
@ -677,8 +704,8 @@ stackargslooparmFuncR0R1:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0R1:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
@ -697,3 +724,6 @@ nomoreargsarmFuncR0R1:
|
||||
|
||||
#endif /* arm */
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -34,6 +34,8 @@
|
||||
This code was adapted from as_callfunc_arm_gcc (ARM, Linux hard float) by Brandon Bare on October 2014.
|
||||
*/
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#ifdef __psp2__
|
||||
|
||||
.syntax unified
|
||||
@ -61,7 +63,7 @@
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFunc:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr} /* sp must be 8-byte alignment for ABI compliance, so the pushed registers must be even */
|
||||
|
||||
@ -81,19 +83,19 @@ armFunc:
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r1, [r6, #4]
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6, #8]
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6, #12]
|
||||
|
||||
stackargs:
|
||||
@ -128,11 +130,11 @@ nomoreargs:
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncObjLast:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr} /* We´re storing r11 just to keep the stack aligned to an 8 byte boundary */
|
||||
|
||||
@ -157,28 +159,28 @@ armFuncObjLast:
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r1, [r6,#4]
|
||||
|
||||
it lt
|
||||
it lt
|
||||
movlt r1, r5
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6,#8]
|
||||
|
||||
it lt
|
||||
it lt
|
||||
movlt r2, r5
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6,#12]
|
||||
|
||||
ittt lt
|
||||
ittt lt
|
||||
movlt r3, r5
|
||||
movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */
|
||||
blt stackargsFuncObjLast /* If objlast got placed into a register, go to stackargsFuncObjLast */
|
||||
@ -220,11 +222,11 @@ nomoreargsarmFuncObjLast:
|
||||
|
||||
pop {r4-r8, r10,r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0ObjLast:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr}
|
||||
|
||||
@ -252,35 +254,35 @@ armFuncR0ObjLast:
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6,#4]
|
||||
|
||||
it lt
|
||||
it lt
|
||||
movlt r2, r5
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6,#8]
|
||||
|
||||
ittt lt
|
||||
ittt lt
|
||||
movlt r3, r5
|
||||
movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */
|
||||
blt stackargsFuncR0ObjLast /* If objlast got placed into a register, go to stackargsFuncR0ObjLast */
|
||||
|
||||
cmp r7, #16 /* Else if we have one last arg set the offset accordingly and store the arg in the array */
|
||||
|
||||
itt ge
|
||||
itt ge
|
||||
ldrge r7, [r6, #12]
|
||||
strge r7, [r6, #8]
|
||||
|
||||
str r5, [r6, #12] /* Put objlast in r6 + 12 */
|
||||
mov r5, #0
|
||||
mov r5, #0
|
||||
|
||||
it ge
|
||||
it ge
|
||||
movge r5, #4 /* Set r5 with an offset of #4 if there´s one last arg that couldn´t be placed in r registers */
|
||||
add r5, r5, #4 /* Set r5 with an offset of + #4, so objlast can be loaded into the stack */
|
||||
|
||||
@ -318,11 +320,11 @@ nomoreargsarmFuncR0ObjLast:
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr}
|
||||
|
||||
@ -344,19 +346,19 @@ armFuncR0:
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6, #4]
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6, #8]
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
it ge
|
||||
movge r11, #4 /* If there is still one arg to be placed, set the offset in r11 to #4 */
|
||||
|
||||
stackargsarmFuncR0:
|
||||
@ -393,11 +395,11 @@ nomoreargsarmFuncR0:
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0R1:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr}
|
||||
|
||||
@ -421,23 +423,23 @@ armFuncR0R1:
|
||||
/* Load the first 2 arguments into r2-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6, #4]
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
movge r11, #4 /* If there is a third arg to be placed, set the offset in r11 to #4 */
|
||||
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
it ge
|
||||
movge r11, #8 /* If there is a fourth arg to be placed, set the offset in r11 to #8 */
|
||||
|
||||
itt lt
|
||||
itt lt
|
||||
ldrlt r7, [r6, #8] /* Else copy the third arg to the correct place in the array */
|
||||
strlt r7, [r6, #12]
|
||||
|
||||
@ -475,6 +477,9 @@ nomoreargsarmFuncR0R1:
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2009 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -35,6 +35,8 @@
|
||||
// Adapted to GNUC by darktemplar216 in September 2009
|
||||
// Small fixed to work under XCode GCC by Gilad Novik in October 2009
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#if defined(__arm__) || defined(__ARM__)
|
||||
|
||||
.align 2
|
||||
@ -235,3 +237,6 @@ nomoreargsarmFuncR0R1:
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -35,7 +35,9 @@
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
// This version is MIPS specific and was originally written
|
||||
// by Manu Evans in April, 2006
|
||||
// by Manu Evans in April, 2006 for Playstation Portable (PSP)
|
||||
//
|
||||
// Support for Linux with MIPS was added by Andreas Jonsson in April, 2015
|
||||
//
|
||||
|
||||
|
||||
@ -52,10 +54,320 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if !defined(AS_ANDROID)
|
||||
#include <regdef.h>
|
||||
#endif
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#if defined(__linux__) && defined(_ABIO32)
|
||||
|
||||
// The MIPS ABI used by Linux is implemented here
|
||||
// (Tested on CI20 MIPS Creator with Debian Linux)
|
||||
//
|
||||
// ref: SYSTEM V
|
||||
// APPLICATION BINARY INTERFACE
|
||||
// MIPS RISC Processor
|
||||
// http://math-atlas.sourceforge.net/devel/assembly/mipsabi32.pdf
|
||||
//
|
||||
// ref: MIPS Instruction Reference
|
||||
// http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html
|
||||
|
||||
union SFloatRegs
|
||||
{
|
||||
union { double d0; struct { float f0; asDWORD dummy0; };};
|
||||
union { double d1; struct { float f1; asDWORD dummy1; };};
|
||||
} ;
|
||||
|
||||
extern "C" asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs);
|
||||
asDWORD GetReturnedFloat();
|
||||
asQWORD GetReturnedDouble();
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
|
||||
void *func = (void*)sysFunc->func;
|
||||
void **vftable;
|
||||
|
||||
asDWORD argBuffer[128]; // Ought to be big enough
|
||||
asASSERT( sysFunc->paramSize < 128 );
|
||||
|
||||
asDWORD argOffset = 0;
|
||||
|
||||
SFloatRegs floatRegs;
|
||||
asDWORD floatOffset = 0;
|
||||
|
||||
// If the application function returns the value in memory then
|
||||
// the first argument must be the pointer to that memory
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
asASSERT( retPointer );
|
||||
argBuffer[argOffset++] = (asPWORD)retPointer;
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_THISCALL || callConv == ICC_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the first argument
|
||||
argBuffer[argOffset++] = (asPWORD)obj;
|
||||
}
|
||||
|
||||
if( callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM )
|
||||
{
|
||||
// Add the second object pointer
|
||||
argBuffer[argOffset++] = (asPWORD)secondObject;
|
||||
}
|
||||
|
||||
int spos = 0;
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
asCDataType ¶mType = descr->parameterTypes[n];
|
||||
if( paramType.IsObject() && !paramType.IsObjectHandle() && !paramType.IsReference() )
|
||||
{
|
||||
if( paramType.GetObjectType()->flags & COMPLEX_MASK )
|
||||
{
|
||||
// The object is passed by reference
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure 8byte alignment for classes that need it
|
||||
if( (paramType.GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) )
|
||||
argOffset++;
|
||||
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(&argBuffer[argOffset], *(void**)(args+spos), paramType.GetSizeInMemoryBytes());
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos++;
|
||||
argOffset += paramType.GetSizeInMemoryDWords();
|
||||
}
|
||||
}
|
||||
else if( paramType.GetTokenType() == ttQuestion )
|
||||
{
|
||||
// Copy both pointer and type id
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The first 2 floats or doubles are loaded into the float registers.
|
||||
// Actually this is only done if they are the first arguments to the function,
|
||||
// but it doesn't cause any harm to load them into the registers even if they
|
||||
// won't be used so we don't need to check if they really are the first args.
|
||||
if( floatOffset == 0 )
|
||||
{
|
||||
if( paramType.GetTokenType() == ttFloat )
|
||||
floatRegs.f0 = *reinterpret_cast<float*>(&args[spos]);
|
||||
else if( paramType.GetTokenType() == ttDouble )
|
||||
floatRegs.d0 = *reinterpret_cast<double*>(&args[spos]);
|
||||
floatOffset++;
|
||||
}
|
||||
else if( floatOffset == 1 )
|
||||
{
|
||||
if( paramType.GetTokenType() == ttFloat )
|
||||
floatRegs.f1 = *reinterpret_cast<float*>(&args[spos]);
|
||||
else if( paramType.GetTokenType() == ttDouble )
|
||||
floatRegs.d1 = *reinterpret_cast<double*>(&args[spos]);
|
||||
floatOffset++;
|
||||
}
|
||||
|
||||
// Copy the value directly
|
||||
if( paramType.GetSizeOnStackDWords() > 1 )
|
||||
{
|
||||
// Make sure the argument is 8byte aligned
|
||||
if( argOffset & 1 )
|
||||
argOffset++;
|
||||
*reinterpret_cast<asQWORD*>(&argBuffer[argOffset]) = *reinterpret_cast<asQWORD*>(&args[spos]);
|
||||
argOffset += 2;
|
||||
spos += 2;
|
||||
}
|
||||
else
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
}
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the last argument
|
||||
argBuffer[argOffset++] = (asPWORD)obj;
|
||||
}
|
||||
|
||||
if( callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the second object pointer
|
||||
argBuffer[argOffset++] = (asPWORD)secondObject;
|
||||
}
|
||||
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL:
|
||||
case ICC_CDECL_RETURNINMEM:
|
||||
case ICC_STDCALL:
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJLAST:
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJFIRST:
|
||||
case ICC_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJLAST:
|
||||
case ICC_THISCALL_OBJLAST_RETURNINMEM:
|
||||
retQW = mipsFunc(argOffset*4, argBuffer, func, floatRegs);
|
||||
break;
|
||||
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(void***)obj;
|
||||
retQW = mipsFunc(argOffset*4, argBuffer, vftable[asPWORD(func)>>2], floatRegs);
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
asDWORD GetReturnedFloat()
|
||||
{
|
||||
asDWORD f;
|
||||
|
||||
asm("swc1 $f0, %0\n" : "=m"(f));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
asQWORD GetReturnedDouble()
|
||||
{
|
||||
asQWORD d = 0;
|
||||
|
||||
asm("sdc1 $f0, %0\n" : "=m"(d));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
// asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs);
|
||||
// $2,$3 $4 $5 $6 $7
|
||||
asm(
|
||||
" .text\n"
|
||||
//" .align 2\n"
|
||||
" .cfi_startproc\n"
|
||||
" .global mipsFunc\n"
|
||||
" .ent mipsFunc\n"
|
||||
"mipsFunc:\n"
|
||||
//" .frame $fp,64,$31 # vars= 0, regs= 0/0, args= 0, gp= 0\n"
|
||||
//" .mask 0x00000000,0\n"
|
||||
//" .fmask 0x00000000,0\n"
|
||||
" .set noreorder\n"
|
||||
" .set nomacro\n"
|
||||
|
||||
// align the stack frame to 8 bytes
|
||||
" addiu $12, $4, 7\n" // t4 ($12) = argSize ($4) + 7
|
||||
" li $13, -8\n" // t5 ($13) = 0xfffffffffffffff8
|
||||
" and $12, $12, $13\n" // t4 ($12) &= t5 ($13). t4 holds the size of the argument block
|
||||
// It is required that the caller reserves space for at least 16 bytes even if there are less than 4 arguments
|
||||
// and add 8 bytes for the return pointer and s0 ($16) backup
|
||||
" addiu $13, $12, 24\n" // t5 = t4 + 24. t5 ($13) holds the total size of the stack frame (including return pointer)
|
||||
// save the s0 register (so we can use it to remember where our return pointer is lives)
|
||||
" sw $16, -4($sp)\n" // store the s0 register (so we can use it to remember how big our stack frame is)
|
||||
" .cfi_offset 16, -4\n"
|
||||
// store the return pointer
|
||||
" sw $31, -8($sp)\n"
|
||||
" .cfi_offset 31, -8\n"
|
||||
// keep original stack pointer
|
||||
" move $16, $sp\n"
|
||||
" .cfi_def_cfa_register 16\n"
|
||||
// push the stack
|
||||
" subu $sp, $sp, $13\n"
|
||||
|
||||
// store the argument in temporary registers
|
||||
" addiu $25, $6, 0\n" // t9 ($25) holds the function pointer (must be t9 for position independent code)
|
||||
" addiu $3, $4, 0\n" // v1 ($3) holds the size of the argument buffer
|
||||
" move $15, $5\n" // t7 ($15) holds the pointer to the argBuffer
|
||||
" move $14, $7\n" // t6 ($14) holds the values for the float registers
|
||||
|
||||
// load integer registers
|
||||
" lw $4, 0($15)\n" // a0 ($4)
|
||||
" lw $5, 4($15)\n" // a1 ($5)
|
||||
" lw $6, 8($15)\n" // a2 ($6)
|
||||
" lw $7, 12($15)\n" // a3 ($7)
|
||||
|
||||
// load float registers
|
||||
" ldc1 $f12, 8($14)\n"
|
||||
" ldc1 $f14, 0($14)\n"
|
||||
|
||||
// skip stack parameters if there are 4 or less as they are moved into the registers
|
||||
" addi $14, $3, -16\n" // The first 4 args were already loaded into registers
|
||||
" blez $14, andCall\n"
|
||||
" nop\n"
|
||||
|
||||
// push stack parameters
|
||||
"pushArgs:\n"
|
||||
" addi $3, -4\n"
|
||||
// load from $15 + stack bytes ($3)
|
||||
" addu $14, $15, $3\n"
|
||||
" lw $14, 0($14)\n"
|
||||
// store to $sp + stack bytes ($3)
|
||||
" addu $13, $sp, $3\n"
|
||||
" sw $14, 0($13)\n"
|
||||
// if there are more, loop...
|
||||
" bne $3, $0, pushArgs\n"
|
||||
" nop\n"
|
||||
|
||||
// and call the function
|
||||
"andCall:\n"
|
||||
" jalr $25\n"
|
||||
" nop\n"
|
||||
|
||||
// restore original stack pointer
|
||||
" move $sp, $16\n"
|
||||
// restore the return pointer
|
||||
" lw $31, -8($sp)\n"
|
||||
// restore the original value of $16
|
||||
" lw $16, -4($sp)\n"
|
||||
// and return from the function
|
||||
" jr $31\n"
|
||||
" nop\n"
|
||||
|
||||
" .set macro\n"
|
||||
" .set reorder\n"
|
||||
" .end mipsFunc\n"
|
||||
" .cfi_endproc\n"
|
||||
" .size mipsFunc, .-mipsFunc\n"
|
||||
);
|
||||
|
||||
#else // !(defined(__linux__) && defined(_ABIO32))
|
||||
|
||||
// The MIPS ABI used by PSP and PS2 is implemented here
|
||||
|
||||
#define AS_MIPS_MAX_ARGS 32
|
||||
#define AS_NUM_REG_FLOATS 8
|
||||
#define AS_NUM_REG_INTS 8
|
||||
@ -191,33 +503,12 @@ asDWORD GetReturnedFloat()
|
||||
return f;
|
||||
}
|
||||
|
||||
/*
|
||||
asDWORD GetReturnedFloat();
|
||||
|
||||
asm(
|
||||
" .align 4\n"
|
||||
" .global GetReturnedFloat\n"
|
||||
"GetReturnedFloat:\n"
|
||||
" .set noreorder\n"
|
||||
" .set nomacro\n"
|
||||
" j $ra\n"
|
||||
" mfc1 $v0, $f0\n"
|
||||
" .set macro\n"
|
||||
" .set reorder\n"
|
||||
" .end Func\n"
|
||||
*/
|
||||
|
||||
|
||||
// sizeof(double) == 4 with sh-elf-gcc (3.4.0) -m4
|
||||
// so this isn't really used...
|
||||
asQWORD GetReturnedDouble()
|
||||
{
|
||||
asQWORD d = 0;
|
||||
|
||||
printf("Broken!!!");
|
||||
/*
|
||||
asm("sw $v0, %0\n" : "=m"(d));
|
||||
*/
|
||||
asm("sdc1 $f0, %0\n" : "=m"(d));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
@ -352,7 +643,7 @@ asm(
|
||||
" .set nomacro\n"
|
||||
// align the stack frame to 8 bytes
|
||||
" addiu $12, $6, 7\n"
|
||||
" li $13, -8\n" // 0xfffffffffffffffc
|
||||
" li $13, -8\n" // 0xfffffffffffffff8
|
||||
" and $12, $12, $13\n" // t4 holds the size of the argument block
|
||||
// and add 8 bytes for the return pointer and s0 backup
|
||||
" addiu $13, $12, 8\n" // t5 holds the total size of the stack frame (including return pointer)
|
||||
@ -432,6 +723,8 @@ asm(
|
||||
" .size mipsFunc, .-mipsFunc\n"
|
||||
);
|
||||
|
||||
#endif // PSP and PS2 MIPS ABI
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_MIPS
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -73,14 +73,18 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i
|
||||
|
||||
__asm__ __volatile__ (
|
||||
|
||||
" movq %0, %%rcx \n" // rcx = cnt
|
||||
" movq %0, %%rcx \n" // rcx = cnt
|
||||
" movq %1, %%r10 \n" // r10 = args
|
||||
" movq %2, %%r11 \n" // r11 = func
|
||||
|
||||
// Backup stack pointer in R15 that is guaranteed to maintain its value over function calls
|
||||
" movq %%rsp, %%r15 \n"
|
||||
#ifdef __OPTIMIZE__
|
||||
// Make sure the stack unwind logic knows we've backed up the stack pointer in register r15
|
||||
// This should only be done if any optimization is done. If no optimization (-O0) is used,
|
||||
// then the compiler already backups the rsp before entering the inline assembler code
|
||||
" .cfi_def_cfa_register r15 \n"
|
||||
#endif
|
||||
|
||||
// Skip the first 128 bytes on the stack frame, called "red zone",
|
||||
// that might be used by the compiler to store temporary values
|
||||
@ -100,7 +104,7 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i
|
||||
" jle endstack \n"
|
||||
" subl $1, %%esi \n"
|
||||
" xorl %%edx, %%edx \n"
|
||||
" leaq 8(, %%rsi, 8), %%rcx \n"
|
||||
" leaq 8(, %%rsi, 8), %%rcx \n"
|
||||
"loopstack: \n"
|
||||
" movq 112(%%r10, %%rdx), %%rax \n"
|
||||
" pushq %%rax \n"
|
||||
@ -128,12 +132,16 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i
|
||||
" movsd 56(%%rax), %%xmm7 \n"
|
||||
|
||||
// Call the function
|
||||
" call *%%r11 \n"
|
||||
" call *%%r11 \n"
|
||||
|
||||
// Restore stack pointer
|
||||
" mov %%r15, %%rsp \n"
|
||||
#ifdef __OPTIMIZE__
|
||||
// Inform the stack unwind logic that the stack pointer has been restored
|
||||
// This should only be done if any optimization is done. If no optimization (-O0) is used,
|
||||
// then the compiler already backups the rsp before entering the inline assembler code
|
||||
" .cfi_def_cfa_register rsp \n"
|
||||
#endif
|
||||
|
||||
// Put return value in retQW1 and retQW2, using either RAX:RDX or XMM0:XMM1 depending on type of return value
|
||||
" movl %5, %%ecx \n"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -1263,13 +1263,13 @@ endcopy:
|
||||
"subl $4, %%ecx \n"
|
||||
"jne copyloop3 \n"
|
||||
"endcopy3: \n"
|
||||
#if defined(__MINGW32__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4)
|
||||
// MinGW made some strange choices with 4.7, and the thiscall calling convention
|
||||
// when returning an object in memory is completely different from when not returning
|
||||
// in memory
|
||||
"pushl 0(%%ebx) \n" // push obj on the stack
|
||||
"movl 16(%%ebx), %%ecx \n" // move the return pointer into ECX
|
||||
"call *12(%%ebx) \n" // call the function
|
||||
#ifdef AS_MINGW47
|
||||
// MinGW made some strange choices with 4.7 and the thiscall calling convention,
|
||||
// returning an object in memory is completely different from when not returning
|
||||
// in memory
|
||||
"pushl 0(%%ebx) \n" // push obj on the stack
|
||||
"movl 16(%%ebx), %%ecx \n" // move the return pointer into ECX
|
||||
"call *12(%%ebx) \n" // call the function
|
||||
#else
|
||||
"movl 0(%%ebx), %%ecx \n" // move obj into ECX
|
||||
#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
@ -1286,7 +1286,7 @@ endcopy:
|
||||
"addl $4, %%esp \n" // pop the object pointer
|
||||
#endif
|
||||
#endif
|
||||
#endif // MINGW
|
||||
#endif // AS_MINGW47
|
||||
// Pop the alignment bytes
|
||||
"popl %%esp \n"
|
||||
"popl %%ebx \n"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -43,7 +43,9 @@
|
||||
// various fixes in asm ppcFunc
|
||||
// fix for variable arguments
|
||||
//
|
||||
|
||||
// Modified by Anthony Clark May 2015
|
||||
// Fixed the issue where int64 and uint64 could not be passed nativly
|
||||
// few minor fixes within asm ppcFunc to handle int64 and uint64
|
||||
|
||||
|
||||
// XBox 360 calling convention
|
||||
@ -87,7 +89,6 @@
|
||||
// References:
|
||||
// https://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF77852569970071B0D6/$file/eabi_app.pdf
|
||||
//
|
||||
// TODO: The code doesn't handle int64 and uint64 parameters
|
||||
// TODO: The code doesn't handle objects passed by value (unless they are max 4 bytes in size)
|
||||
|
||||
|
||||
@ -128,7 +129,7 @@ enum argTypes
|
||||
// pArgs is the array of the argument values
|
||||
// pArgTypes is an array containing a byte indicating the type (enum argTypes) for each argument.
|
||||
// dwFunc is the address of the function that will be called
|
||||
asQWORD __declspec( naked ) ppcFunc(const asDWORD* pArgs, asDWORD dwFunc, const asBYTE* pArgTypes)
|
||||
asQWORD __declspec( naked ) ppcFunc(const asQWORD* pArgs, asDWORD dwFunc, const asBYTE* pArgTypes)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
@ -202,7 +203,7 @@ ppcNextArg:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ppcArgIsInteger:
|
||||
// Get the arg from the stack
|
||||
lwz r12, 0(r26)
|
||||
ld r12, 0(r26)
|
||||
|
||||
// r23 holds the integer arg count so far
|
||||
cmplwi cr6, r23, 0
|
||||
@ -251,11 +252,11 @@ ppcArgIsInteger:
|
||||
b ppcLoadIntRegUpd
|
||||
|
||||
ppcLoadIntRegUpd:
|
||||
stw r12, 0(r31) // push on the stack
|
||||
std r12, 0(r31) // push on the stack
|
||||
addi r31, r31, 8 // inc stack by 1 reg
|
||||
|
||||
addi r23, r23, 1 // Increment used int register count
|
||||
addi r26, r26, 4 // Increment pArgs
|
||||
addi r26, r26, 8 // Increment pArgs
|
||||
b ppcNextArg // Call next arg
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -511,7 +512,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
|
||||
// Pack the arguments into an array that ppcFunc() can use to load each CPU register properly
|
||||
asBYTE ppcArgsType[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG + AS_PPC_ENDOFARGS];
|
||||
asDWORD ppcArgs[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG];
|
||||
asQWORD ppcArgs[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG];
|
||||
int argsCnt = 0;
|
||||
|
||||
// If the function returns an object in memory, we allocate the memory and put the ptr to the front (will go to r3)
|
||||
@ -625,35 +626,34 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: How should int64 and uint64 be passed natively?
|
||||
// Currently the code doesn't handle these types
|
||||
|
||||
// TODO: The code also ignore the fact that large objects
|
||||
// passed by value has been copied to the stack
|
||||
// in the above loop.
|
||||
|
||||
*pCurArgType++ = ppcINTARG;
|
||||
|
||||
*((int*) pCurFixedArgValue) = *((int*) pCurStackArgValue);
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asUINT*) pCurStackArgValue);
|
||||
|
||||
if( !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
// If the arg is less that 4 bytes, then move the
|
||||
// bytes to the higher bytes within the dword
|
||||
// If the arg is not 4 bytes which we coppied, lets do it again the right way
|
||||
asUINT numBytes = descr->parameterTypes[n].GetSizeInMemoryBytes();
|
||||
if( numBytes == 1 )
|
||||
{
|
||||
pCurFixedArgValue[3] = pCurFixedArgValue[0];
|
||||
pCurFixedArgValue[0] = 0;
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asBYTE*) pCurStackArgValue);
|
||||
}
|
||||
else if( numBytes == 2 )
|
||||
{
|
||||
*(asWORD*)&pCurFixedArgValue[2] = *(asWORD*)&pCurFixedArgValue[0];
|
||||
*(asWORD*)&pCurFixedArgValue[0] = 0;
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asWORD*) pCurStackArgValue);
|
||||
}
|
||||
else if( numBytes == 8 )
|
||||
{
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asQWORD*) pCurStackArgValue);
|
||||
pCurStackArgValue += 4; // Increase our cur stack arg value by 4 bytes to = 8 total later
|
||||
}
|
||||
}
|
||||
|
||||
pCurFixedArgValue += 4;
|
||||
pCurFixedArgValue += 8;
|
||||
pCurStackArgValue += 4;
|
||||
|
||||
// if it is a variable argument, account for the typeId
|
||||
@ -703,7 +703,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
// Add the object pointer as the last argument
|
||||
ppcArgsType[argsCnt++] = ppcINTARG;
|
||||
ppcArgsType[argsCnt] = ppcENDARG;
|
||||
*((asPWORD*)pCurFixedArgValue) = (asPWORD)obj;
|
||||
*((asQWORD*)pCurFixedArgValue) = (asPWORD)obj;
|
||||
retQW = ppcFunc( ppcArgs, (asDWORD)func, ppcArgsType );
|
||||
break;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -73,14 +73,9 @@ struct asSExprContext
|
||||
{
|
||||
asSExprContext(asCScriptEngine *engine) : bc(engine)
|
||||
{
|
||||
exprNode = 0;
|
||||
origExpr = 0;
|
||||
property_get = 0;
|
||||
property_set = 0;
|
||||
property_const = false;
|
||||
property_handle = false;
|
||||
property_ref = false;
|
||||
property_arg = 0;
|
||||
property_arg = 0;
|
||||
|
||||
Clear();
|
||||
}
|
||||
~asSExprContext()
|
||||
{
|
||||
@ -90,43 +85,95 @@ struct asSExprContext
|
||||
void Clear()
|
||||
{
|
||||
bc.ClearAll();
|
||||
type.SetDummy();
|
||||
type.Set(asCDataType());
|
||||
deferredParams.SetLength(0);
|
||||
if( property_arg )
|
||||
asDELETE(property_arg, asSExprContext);
|
||||
property_arg = 0;
|
||||
deferredParams.SetLength(0);
|
||||
exprNode = 0;
|
||||
origExpr = 0;
|
||||
property_get = 0;
|
||||
property_set = 0;
|
||||
property_const = false;
|
||||
property_handle = false;
|
||||
property_ref = false;
|
||||
methodName = "";
|
||||
enumValue = "";
|
||||
property_arg = 0;
|
||||
exprNode = 0;
|
||||
origExpr = 0;
|
||||
property_get = 0;
|
||||
property_set = 0;
|
||||
property_const = false;
|
||||
property_handle = false;
|
||||
property_ref = false;
|
||||
methodName = "";
|
||||
enumValue = "";
|
||||
isVoidExpression = false;
|
||||
isCleanArg = false;
|
||||
}
|
||||
bool IsClassMethod()
|
||||
bool IsClassMethod() const
|
||||
{
|
||||
if( type.dataType.GetObjectType() == 0 ) return false;
|
||||
if( methodName == "" ) return false;
|
||||
if( type.dataType.GetObjectType() == &type.dataType.GetObjectType()->engine->functionBehaviours ) return false;
|
||||
return true;
|
||||
}
|
||||
bool IsGlobalFunc()
|
||||
bool IsGlobalFunc() const
|
||||
{
|
||||
if( type.dataType.GetObjectType() == 0 ) return false;
|
||||
if( methodName == "" ) return false;
|
||||
if( type.dataType.GetObjectType() != &type.dataType.GetObjectType()->engine->functionBehaviours ) return false;
|
||||
return true;
|
||||
}
|
||||
void SetLambda(asCScriptNode *funcDecl)
|
||||
{
|
||||
asASSERT( funcDecl && funcDecl->nodeType == snFunction );
|
||||
asASSERT( bc.GetLastInstr() == -1 );
|
||||
|
||||
Clear();
|
||||
type.SetUndefinedFuncHandle(bc.GetEngine());
|
||||
exprNode = funcDecl;
|
||||
}
|
||||
bool IsLambda() const
|
||||
{
|
||||
if( type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
void SetVoidExpression()
|
||||
{
|
||||
Clear();
|
||||
type.SetVoid();
|
||||
isVoidExpression = true;
|
||||
}
|
||||
bool IsVoidExpression() const
|
||||
{
|
||||
if( isVoidExpression && type.IsVoid() && exprNode == 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
void Merge(asSExprContext *after)
|
||||
{
|
||||
type = after->type;
|
||||
property_get = after->property_get;
|
||||
property_set = after->property_set;
|
||||
property_const = after->property_const;
|
||||
property_handle = after->property_handle;
|
||||
property_ref = after->property_ref;
|
||||
property_arg = after->property_arg;
|
||||
exprNode = after->exprNode;
|
||||
methodName = after->methodName;
|
||||
enumValue = after->enumValue;
|
||||
isVoidExpression = after->isVoidExpression;
|
||||
isCleanArg = after->isCleanArg;
|
||||
|
||||
after->property_arg = 0;
|
||||
|
||||
// Do not copy the origExpr member
|
||||
}
|
||||
|
||||
asCByteCode bc;
|
||||
asCTypeInfo type;
|
||||
int property_get;
|
||||
int property_set;
|
||||
bool property_const; // If the object that is being accessed through property accessor is read-only
|
||||
bool property_handle; // If the property accessor is called on an object stored in a handle
|
||||
bool property_ref; // If the property accessor is called on a reference
|
||||
bool property_const; // If the object that is being accessed through property accessor is read-only
|
||||
bool property_handle; // If the property accessor is called on an object stored in a handle
|
||||
bool property_ref; // If the property accessor is called on a reference
|
||||
bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls
|
||||
bool isCleanArg; // Set to true if the expression has only been initialized with default constructor
|
||||
asSExprContext *property_arg;
|
||||
asCArray<asSDeferredParam> deferredParams;
|
||||
asCScriptNode *exprNode;
|
||||
@ -212,8 +259,8 @@ protected:
|
||||
int CompileExpressionPostOp(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileExpressionValue(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileFunctionCall(asCScriptNode *node, asSExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = "");
|
||||
void CompileConstructCall(asCScriptNode *node, asSExprContext *out);
|
||||
void CompileConversion(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileConstructCall(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileConversion(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileMathOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
@ -239,6 +286,7 @@ protected:
|
||||
void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination);
|
||||
|
||||
// Helper functions
|
||||
void ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix);
|
||||
void ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node);
|
||||
int ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node);
|
||||
int ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, eTokenType op, asCScriptNode *errNode);
|
||||
@ -288,6 +336,7 @@ protected:
|
||||
asUINT ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode);
|
||||
void ImplicitConversionConstant(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType);
|
||||
void ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node);
|
||||
asUINT ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true);
|
||||
|
||||
void LineInstr(asCByteCode *bc, size_t pos);
|
||||
|
||||
@ -307,16 +356,18 @@ protected:
|
||||
bool hasCompileErrors;
|
||||
|
||||
int nextLabel;
|
||||
int numLambdas;
|
||||
|
||||
asCVariableScope *variables;
|
||||
asCBuilder *builder;
|
||||
asCScriptEngine *engine;
|
||||
asCScriptCode *script;
|
||||
asCVariableScope *variables;
|
||||
asCBuilder *builder;
|
||||
asCScriptEngine *engine;
|
||||
asCScriptCode *script;
|
||||
asCScriptFunction *outFunc;
|
||||
|
||||
bool m_isConstructor;
|
||||
bool m_isConstructorCalled;
|
||||
sClassDeclaration *m_classDecl;
|
||||
bool m_isConstructor;
|
||||
bool m_isConstructorCalled;
|
||||
sClassDeclaration *m_classDecl;
|
||||
sGlobalVariableDescription *m_globalVar;
|
||||
|
||||
asCArray<int> breakLabels;
|
||||
asCArray<int> continueLabels;
|
||||
@ -353,7 +404,7 @@ protected:
|
||||
|
||||
bool isCompilingDefaultArg;
|
||||
bool isProcessingDeferredParams;
|
||||
int noCodeOutput;
|
||||
int noCodeOutput;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -586,6 +586,7 @@
|
||||
#define AS_NO_MEMORY_H
|
||||
#define AS_MIPS
|
||||
#define AS_PSP
|
||||
#define AS_USE_DOUBLE_AS_FLOAT
|
||||
// PSVita
|
||||
#elif defined(__psp2__)
|
||||
#define AS_PSVITA
|
||||
@ -799,6 +800,14 @@
|
||||
// As of version 4.7 MinGW changed the ABI, presumably
|
||||
// to be better aligned with how MSVC works
|
||||
#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4
|
||||
#define AS_MINGW47
|
||||
#endif
|
||||
|
||||
#if (__clang_major__ == 3 && __clang_minor__ > 4) || __clang_major > 3
|
||||
#define AS_MINGW47
|
||||
#endif
|
||||
|
||||
#ifdef AS_MINGW47
|
||||
#undef CALLEE_POPS_HIDDEN_RETURN_POINTER
|
||||
#define THISCALL_CALLEE_POPS_ARGUMENTS
|
||||
#else
|
||||
@ -845,7 +854,7 @@
|
||||
// STDCALL is not available on 64bit Linux
|
||||
#undef STDCALL
|
||||
#define STDCALL
|
||||
#elif defined(__ARMEL__) || defined(__arm__)
|
||||
#elif (defined(__ARMEL__) || defined(__arm__)) && !(defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__))
|
||||
#define AS_ARM
|
||||
|
||||
// TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S
|
||||
@ -884,11 +893,24 @@
|
||||
|
||||
#elif defined(__mips__)
|
||||
#define AS_MIPS
|
||||
#define AS_BIG_ENDIAN
|
||||
#define AS_USE_DOUBLE_AS_FLOAT
|
||||
#undef STDCALL
|
||||
#define STDCALL
|
||||
|
||||
// Native calling conventions for Linux/Mips do not work yet.
|
||||
#define AS_MAX_PORTABILITY
|
||||
#ifdef _ABIO32
|
||||
#define AS_MIPS
|
||||
|
||||
// All structures are returned in memory regardless of size or complexity
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#else
|
||||
// For other ABIs the native calling convention is not available (yet)
|
||||
#define AS_MAX_PORTABILITY
|
||||
#endif
|
||||
#else
|
||||
#define AS_MAX_PORTABILITY
|
||||
#endif
|
||||
@ -936,6 +958,7 @@
|
||||
// Support native calling conventions on MIPS architecture
|
||||
#if (defined(_MIPS_ARCH) || defined(_mips) || defined(__MIPSEL__)) && !defined(__LP64__)
|
||||
#define AS_MIPS
|
||||
#define AS_USE_DOUBLE_AS_FLOAT
|
||||
#else
|
||||
#define AS_MAX_PORTABILITY
|
||||
#endif
|
||||
@ -988,6 +1011,9 @@
|
||||
#if (defined(_ARM_) || defined(__arm__))
|
||||
// Android ARM
|
||||
|
||||
// TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S
|
||||
#define AS_NO_EXCEPTIONS
|
||||
|
||||
#undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
#undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
#undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
@ -1013,6 +1039,26 @@
|
||||
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
#define AS_X86
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#elif defined(__mips__)
|
||||
#define AS_MIPS
|
||||
#undef STDCALL
|
||||
#define STDCALL
|
||||
|
||||
#ifdef _ABIO32
|
||||
#define AS_MIPS
|
||||
|
||||
// All structures are returned in memory regardless of size or complexity
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#else
|
||||
// For other ABIs the native calling convention is not available (yet)
|
||||
#define AS_MAX_PORTABILITY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Haiku OS
|
||||
@ -1047,7 +1093,7 @@
|
||||
// Support native calling conventions on Intel 32bit CPU
|
||||
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
#define AS_X86
|
||||
#elif defined(__LP64__)
|
||||
#elif defined(__x86_64__)
|
||||
#define AS_X64_GCC
|
||||
#define HAS_128_BIT_PRIMITIVES
|
||||
#define SPLIT_OBJS_BY_MEMBER_TYPES
|
||||
@ -1112,11 +1158,6 @@
|
||||
// Nothing special here
|
||||
#endif
|
||||
|
||||
// MIPS architecture (generally PS2 and PSP consoles, potentially supports N64 as well)
|
||||
#if defined(_MIPS_ARCH) || defined(_mips) || defined(__MIPSEL__) || defined(__PSP__) || defined(__psp__) || defined(_EE_) || defined(_PSP) || defined(_PS2)
|
||||
#define AS_USE_DOUBLE_AS_FLOAT // use 32bit floats instead of doubles
|
||||
#endif
|
||||
|
||||
// PowerPC, e.g. Mac, GameCube, PS3, XBox 360, Wii
|
||||
#if defined(__PPC__) || defined(__ppc__) || defined(_PPC_) || defined(EPPC)
|
||||
#define AS_BIG_ENDIAN
|
||||
|
@ -134,17 +134,32 @@ public:
|
||||
|
||||
#endif
|
||||
|
||||
// interface
|
||||
AS_API asIScriptContext *asGetActiveContext()
|
||||
{
|
||||
asCThreadLocalData *tld = asCThreadManager::GetLocalData();
|
||||
if( tld->activeContexts.GetLength() == 0 )
|
||||
|
||||
// tld can be 0 if asGetActiveContext is called before any engine has been created.
|
||||
|
||||
// Observe! I've seen a case where an application linked with the library twice
|
||||
// and thus ended up with two separate instances of the code and global variables.
|
||||
// The application somehow mixed the two instances so that a function called from
|
||||
// a script ended up calling asGetActiveContext from the other instance that had
|
||||
// never been initialized.
|
||||
|
||||
if( tld == 0 || tld->activeContexts.GetLength() == 0 )
|
||||
return 0;
|
||||
return tld->activeContexts[tld->activeContexts.GetLength()-1];
|
||||
}
|
||||
|
||||
// internal
|
||||
// Note: There is no asPopActiveContext(), just call tld->activeContexts.PopLast() instead
|
||||
asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx)
|
||||
{
|
||||
asCThreadLocalData *tld = asCThreadManager::GetLocalData();
|
||||
asASSERT( tld );
|
||||
if( tld == 0 )
|
||||
return 0;
|
||||
tld->activeContexts.PushLast(ctx);
|
||||
return tld;
|
||||
}
|
||||
@ -1304,8 +1319,9 @@ int asCContext::Execute()
|
||||
}
|
||||
|
||||
// Pop the active context
|
||||
asASSERT(tld->activeContexts[tld->activeContexts.GetLength()-1] == this);
|
||||
tld->activeContexts.PopLast();
|
||||
asASSERT(tld && tld->activeContexts[tld->activeContexts.GetLength()-1] == this);
|
||||
if( tld )
|
||||
tld->activeContexts.PopLast();
|
||||
|
||||
if( m_status == asEXECUTION_FINISHED )
|
||||
{
|
||||
@ -4301,6 +4317,67 @@ void asCContext::ExecuteNext()
|
||||
}
|
||||
l_bc += 2;
|
||||
break;
|
||||
case asBC_Thiscall1:
|
||||
// This instruction is a faster version of asBC_CALLSYS. It is faster because
|
||||
// it has much less runtime overhead with determining the calling convention
|
||||
// and no dynamic code for loading the parameters. The instruction can only
|
||||
// be used to call functions with the following signatures:
|
||||
//
|
||||
// type &obj::func(int)
|
||||
// type &obj::func(uint)
|
||||
// void obj::func(int)
|
||||
// void obj::func(uint)
|
||||
{
|
||||
// Get function ID from the argument
|
||||
int i = asBC_INTARG(l_bc);
|
||||
|
||||
// Need to move the values back to the context as the called functions
|
||||
// may use the debug interface to inspect the registers
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
// Pop the thispointer from the stack
|
||||
void *obj = *(void**)l_sp;
|
||||
l_sp += AS_PTR_SIZE;
|
||||
|
||||
// Pop the int arg from the stack
|
||||
int arg = *(int*)l_sp;
|
||||
l_sp++;
|
||||
|
||||
// Call the method
|
||||
m_callingSystemFunction = m_engine->scriptFunctions[i];
|
||||
void *ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction);
|
||||
m_callingSystemFunction = 0;
|
||||
*(asPWORD*)&m_regs.valueRegister = (asPWORD)ptr;
|
||||
|
||||
// Update the program position after the call so that line number is correct
|
||||
l_bc += 2;
|
||||
|
||||
if( m_regs.doProcessSuspend )
|
||||
{
|
||||
// Should the execution be suspended?
|
||||
if( m_doSuspend )
|
||||
{
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
m_status = asEXECUTION_SUSPENDED;
|
||||
return;
|
||||
}
|
||||
// An exception might have been raised
|
||||
if( m_status != asEXECUTION_ACTIVE )
|
||||
{
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Don't let the optimizer optimize for size,
|
||||
// since it requires extra conditions and jumps
|
||||
@ -4887,7 +4964,7 @@ int asCContext::GetExceptionLineNumber(int *column, const char **sectionName)
|
||||
|
||||
if( sectionName )
|
||||
{
|
||||
// The section index can be -1 if the exception was raised in a generated function, e.g. factstub for templates
|
||||
// The section index can be -1 if the exception was raised in a generated function, e.g. $fact for templates
|
||||
if( m_exceptionSectionIdx >= 0 )
|
||||
*sectionName = m_engine->scriptSectionNames[m_exceptionSectionIdx]->AddressOf();
|
||||
else
|
||||
|
@ -227,7 +227,7 @@ asCString asCDataType::Format(asSNameSpace *currNs, bool includeNamespace) const
|
||||
str += "const";
|
||||
}
|
||||
|
||||
if( isReference )
|
||||
if( isReference )
|
||||
str += "&";
|
||||
|
||||
return str;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -74,11 +74,19 @@ typedef double float64_t;
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#endif // AS_PSVITA
|
||||
#endif // _WIN32_WCE
|
||||
#endif // AS_WII
|
||||
|
||||
#endif // !defined(AS_DEBUG)
|
||||
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && defined(AS_PROFILE)
|
||||
// Currently only do profiling with MSVC++
|
||||
|
||||
#include <mmsystem.h>
|
||||
#include <direct.h>
|
||||
#include "as_string.h"
|
||||
#include "as_map.h"
|
||||
#include "as_string_util.h"
|
||||
@ -144,7 +152,7 @@ public:
|
||||
return time;
|
||||
}
|
||||
|
||||
void End(const char *name, double beginTime)
|
||||
void End(const char * /*name*/, double beginTime)
|
||||
{
|
||||
double time = GetTime();
|
||||
|
||||
@ -247,7 +255,7 @@ protected:
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#else // _MSC_VER && AS_PROFILE
|
||||
#else // !(_MSC_VER && AS_PROFILE)
|
||||
|
||||
// Define it so nothing is done
|
||||
#define TimeIt(x)
|
||||
@ -257,20 +265,6 @@ END_AS_NAMESPACE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // AS_PSVITA
|
||||
#endif // _WIN32_WCE
|
||||
#endif // AS_WII
|
||||
|
||||
#else // !defined(AS_DEBUG)
|
||||
|
||||
// Define it so nothing is done
|
||||
#define TimeIt(x)
|
||||
|
||||
#endif // !defined(AS_DEBUG)
|
||||
|
||||
#endif
|
||||
#endif // defined(AS_DEBUG_H)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -486,23 +486,18 @@ int asCGarbageCollector::ReportAndReleaseUndestroyedObjects()
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
|
||||
|
||||
// Add additional info for builtin types
|
||||
if( gcObj.type->name == "_builtin_function_" )
|
||||
if( gcObj.type->name == "$func" )
|
||||
{
|
||||
// Unfortunately we can't show the function declaration here, because the engine may have released the parameter list already so the declaration would only be misleading
|
||||
// We need to show the function type too as for example delegates do not have a name
|
||||
msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, reinterpret_cast<asCScriptFunction*>(gcObj.obj)->GetName(), reinterpret_cast<asCScriptFunction*>(gcObj.obj)->GetFuncType());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
else if( gcObj.type->name == "_builtin_objecttype_" )
|
||||
else if( gcObj.type->name == "$obj" )
|
||||
{
|
||||
msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast<asCObjectType*>(gcObj.obj)->GetName());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
else if( gcObj.type->name == "_builtin_globalprop_" )
|
||||
{
|
||||
msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast<asCGlobalProperty*>(gcObj.obj)->name.AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
|
||||
// Release the reference that the GC holds if the release functions is still available
|
||||
if( gcObj.type->beh.release && engine->scriptFunctions[gcObj.type->beh.release] )
|
||||
|
@ -46,32 +46,6 @@
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// TODO: 2.30.0: redesign: Improved method for discarding modules (faster clean-up, less abuse of garbage collector)
|
||||
//
|
||||
// I need to separate the reference counter for internal references and outside references:
|
||||
//
|
||||
// - Internal references are for example, when the module refers to a function or object since it is declared in the module, or when
|
||||
// a function refers to another function since it is being called in the code.
|
||||
// - Outside references are for example object instances holding a reference to the object type, or a context currently
|
||||
// executing a function.
|
||||
//
|
||||
// If no object instances are alive or no contexts are alive it is known that functions from a discarded module
|
||||
// can be called, so they can be destroyed without any need to execute the complex garbage collection routines.
|
||||
//
|
||||
// If there are live objects, the entire module should be kept for safe keeping, though no longer visible.
|
||||
//
|
||||
// TODO: It may not be necessary to keep track of internal references. Without keeping track of internal references, can I still
|
||||
// handle RemoveFunction and RemoveGlobalVariable correctly?
|
||||
//
|
||||
// TODO: How to avoid global variables keeping code alive? For example a script object, or a funcdef?
|
||||
// Can I do a quick check of the object types and functions to count number of outside references, and then do another
|
||||
// check over the global variables to subtract the outside references coming from these? What if the outside reference
|
||||
// is added by an application type in a global variable that the engine doesn't know about? Example, a global dictionary
|
||||
// holding object instances. Should discarding a module immediately destroy the content of the global variables? What if
|
||||
// a live object tries to access the global variable after it has been discarded? Throwing a script exception is acceptable?
|
||||
// Perhaps I need to allow the user to provide a clean-up routine that will be executed before destroying the objects.
|
||||
// Or I might just put that responsibility on the application.
|
||||
|
||||
|
||||
// internal
|
||||
asCModule::asCModule(const char *name, asCScriptEngine *engine)
|
||||
@ -315,7 +289,7 @@ int asCModule::Build()
|
||||
|
||||
// Don't allow the module to be rebuilt if there are still
|
||||
// external references that will need the previous code
|
||||
// TODO: 2.30.0: interface: The asIScriptModule must have a method for querying if the module is used
|
||||
// TODO: interface: The asIScriptModule must have a method for querying if the module is used
|
||||
if( HasExternalReferences(false) )
|
||||
{
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE);
|
||||
@ -944,9 +918,6 @@ int asCModule::GetGlobalVarIndexByName(const char *name) const
|
||||
// interface
|
||||
int asCModule::RemoveGlobalVar(asUINT index)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Before removing the variable, clear it to free the object
|
||||
// The property shouldn't be orphaned.
|
||||
|
||||
asCGlobalProperty *prop = scriptGlobals.Get(index);
|
||||
if( !prop )
|
||||
return asINVALID_ARG;
|
||||
@ -1273,6 +1244,33 @@ int asCModule::AddScriptFunction(asCScriptFunction *func)
|
||||
func->AddRefInternal();
|
||||
engine->AddScriptFunction(func);
|
||||
|
||||
// If the function that is being added is an already compiled shared function
|
||||
// then it is necessary to look for anonymous functions that may be declared
|
||||
// within it and add those as well
|
||||
if( func->isShared && func->funcType == asFUNC_SCRIPT )
|
||||
{
|
||||
// Loop through the byte code and check all the
|
||||
// asBC_FuncPtr instructions for anonymous functions
|
||||
asDWORD *bc = func->scriptData->byteCode.AddressOf();
|
||||
asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength();
|
||||
for( asUINT n = 0; n < bcLength; )
|
||||
{
|
||||
int c = *(asBYTE*)&bc[n];
|
||||
if( c == asBC_FuncPtr )
|
||||
{
|
||||
asCScriptFunction *f = reinterpret_cast<asCScriptFunction*>(asBC_PTRARG(&bc[n]));
|
||||
// Anonymous functions start with $
|
||||
// There are never two equal anonymous functions so it is not necessary to look for duplicates
|
||||
if( f && f->name[0] == '$' )
|
||||
{
|
||||
AddScriptFunction(f);
|
||||
globalFunctions.Put(f);
|
||||
}
|
||||
}
|
||||
n += asBCTypeSize[asBCInfo[c].type];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1700,16 +1698,6 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li
|
||||
// interface
|
||||
int asCModule::RemoveFunction(asIScriptFunction *func)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Check if there are any references before removing the function
|
||||
// if there are, just hide it from the visible but do not destroy or
|
||||
// remove it from the module.
|
||||
//
|
||||
// Only if the function has no live references, nor internal references
|
||||
// can it be immediately removed, and its internal references released.
|
||||
//
|
||||
// Check if any previously hidden functions are without references,
|
||||
// if so they should removed too.
|
||||
|
||||
// Find the global function
|
||||
asCScriptFunction *f = static_cast<asCScriptFunction*>(func);
|
||||
int idx = globalFunctions.GetIndex(f);
|
||||
@ -1734,6 +1722,7 @@ int asCModule::AddFuncDef(const asCString &name, asSNameSpace *ns)
|
||||
|
||||
func->name = name;
|
||||
func->nameSpace = ns;
|
||||
func->module = this;
|
||||
|
||||
funcDefs.PushLast(func);
|
||||
|
||||
|
@ -53,6 +53,7 @@ asCObjectType::asCObjectType()
|
||||
module = 0;
|
||||
derivedFrom = 0;
|
||||
size = 0;
|
||||
typeId = -1; // start as -1 to signal that it hasn't been defined
|
||||
|
||||
acceptValueSubType = true;
|
||||
acceptRefSubType = true;
|
||||
@ -74,6 +75,7 @@ asCObjectType::asCObjectType(asCScriptEngine *engine)
|
||||
this->engine = engine;
|
||||
module = 0;
|
||||
derivedFrom = 0;
|
||||
typeId = -1; // start as -1 to signal that it hasn't been defined
|
||||
|
||||
acceptValueSubType = true;
|
||||
acceptRefSubType = true;
|
||||
@ -241,7 +243,8 @@ void asCObjectType::DestroyInternal()
|
||||
userData.SetLength(0);
|
||||
|
||||
// Remove the type from the engine
|
||||
engine->RemoveFromTypeIdMap(this);
|
||||
if( typeId != -1 )
|
||||
engine->RemoveFromTypeIdMap(this);
|
||||
|
||||
// Clear the engine pointer to mark the object type as invalid
|
||||
engine = 0;
|
||||
@ -252,7 +255,6 @@ asCObjectType::~asCObjectType()
|
||||
if( engine == 0 )
|
||||
return;
|
||||
|
||||
// TODO: 2.30.0: redesign: Shouldn't this have been done already?
|
||||
DestroyInternal();
|
||||
}
|
||||
|
||||
@ -322,12 +324,18 @@ asUINT asCObjectType::GetSize() const
|
||||
// interface
|
||||
int asCObjectType::GetTypeId() const
|
||||
{
|
||||
// We need a non const pointer to create the asCDataType object.
|
||||
// We're not breaking anything here because this function is not
|
||||
// modifying the object, so this const cast is safe.
|
||||
asCObjectType *ot = const_cast<asCObjectType*>(this);
|
||||
if( typeId == -1 )
|
||||
{
|
||||
// We need a non const pointer to create the asCDataType object.
|
||||
// We're not breaking anything here because this function is not
|
||||
// modifying the object, so this const cast is safe.
|
||||
asCObjectType *ot = const_cast<asCObjectType*>(this);
|
||||
|
||||
return engine->GetTypeIdFromDataType(asCDataType::CreateObject(ot, false));
|
||||
// The engine will define the typeId for this object type
|
||||
engine->GetTypeIdFromDataType(asCDataType::CreateObject(ot, false));
|
||||
}
|
||||
|
||||
return typeId;
|
||||
}
|
||||
|
||||
// interface
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -191,6 +191,7 @@ public:
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
int alignment;
|
||||
#endif
|
||||
mutable int typeId;
|
||||
asCArray<asCObjectProperty*> properties;
|
||||
asCArray<int> methods;
|
||||
asCArray<asCObjectType*> interfaces;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -261,6 +261,13 @@ int asCParser::ParsePropertyDeclaration(asCScriptCode *script)
|
||||
scriptNode->AddChildLast(ParseType(true));
|
||||
if( isSyntaxError ) return -1;
|
||||
|
||||
// Allow optional '&' to indicate that the property is indirect, i.e. stored as reference
|
||||
sToken t;
|
||||
GetToken(&t);
|
||||
RewindTo(&t);
|
||||
if( t.type == ttAmp )
|
||||
scriptNode->AddChildLast(ParseToken(ttAmp));
|
||||
|
||||
// Allow optional namespace to be defined before the identifier in case
|
||||
// the declaration is to be used for searching for an existing property
|
||||
ParseOptionalScope(scriptNode);
|
||||
@ -269,7 +276,6 @@ int asCParser::ParsePropertyDeclaration(asCScriptCode *script)
|
||||
if( isSyntaxError ) return -1;
|
||||
|
||||
// The declaration should end after the identifier
|
||||
sToken t;
|
||||
GetToken(&t);
|
||||
if( t.type != ttEnd )
|
||||
{
|
||||
@ -402,9 +408,11 @@ asCScriptNode *asCParser::ParseType(bool allowConst, bool allowVariableType, boo
|
||||
if( isSyntaxError ) return node;
|
||||
|
||||
// If the datatype is a template type, then parse the subtype within the < >
|
||||
GetToken(&t);
|
||||
RewindTo(&t);
|
||||
asCScriptNode *type = node->lastChild;
|
||||
tempString.Assign(&script->code[type->tokenPos], type->tokenLength);
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) )
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) && t.type == ttLessThan )
|
||||
{
|
||||
GetToken(&t);
|
||||
if( t.type != ttLessThan )
|
||||
@ -602,7 +610,7 @@ asCScriptNode *asCParser::ParseIdentifier()
|
||||
return node;
|
||||
}
|
||||
|
||||
// BNF: PARAMLIST ::= '(' ('void' | (TYPE TYPEMOD [IDENTIFIER] ['=' EXPR] {',' TYPE TYPEMOD [IDENTIFIER] ['=' EXPR]}) ')'
|
||||
// BNF: PARAMLIST ::= '(' ['void' | (TYPE TYPEMOD [IDENTIFIER] ['=' EXPR] {',' TYPE TYPEMOD [IDENTIFIER] ['=' EXPR]})] ')'
|
||||
asCScriptNode *asCParser::ParseParameterList()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snParameterList);
|
||||
@ -1104,10 +1112,13 @@ bool asCParser::CheckTemplateType(sToken &t)
|
||||
tempString.Assign(&script->code[t.pos], t.length);
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) )
|
||||
{
|
||||
// Expect the sub type within < >
|
||||
// If the next token is a < then parse the sub-type too
|
||||
GetToken(&t);
|
||||
if( t.type != ttLessThan )
|
||||
return false;
|
||||
{
|
||||
RewindTo(&t);
|
||||
return true;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@ -1232,7 +1243,7 @@ asCScriptNode *asCParser::ParseCast()
|
||||
return node;
|
||||
}
|
||||
|
||||
// BNF: EXPRVALUE ::= 'void' | CONSTRUCTCALL | FUNCCALL | VARACCESS | CAST | LITERAL | '(' ASSIGN ')'
|
||||
// BNF: EXPRVALUE ::= 'void' | CONSTRUCTCALL | FUNCCALL | VARACCESS | CAST | LITERAL | '(' ASSIGN ')' | LAMBDA
|
||||
asCScriptNode *asCParser::ParseExprValue()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snExprValue);
|
||||
@ -1250,44 +1261,54 @@ asCScriptNode *asCParser::ParseExprValue()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( t1.type == ttIdentifier || t1.type == ttScope )
|
||||
{
|
||||
// Determine the last identifier in order to check if it is a type
|
||||
sToken t;
|
||||
if( t1.type == ttScope ) t = t2; else t = t1;
|
||||
RewindTo(&t);
|
||||
GetToken(&t2);
|
||||
while( t.type == ttIdentifier )
|
||||
// Check if the expression is an anonymous function
|
||||
if( IsLambda() )
|
||||
{
|
||||
t2 = t;
|
||||
GetToken(&t);
|
||||
if( t.type == ttScope )
|
||||
GetToken(&t);
|
||||
else
|
||||
break;
|
||||
node->AddChildLast(ParseLambda());
|
||||
}
|
||||
|
||||
bool isDataType = IsDataType(t2);
|
||||
bool isTemplateType = false;
|
||||
if( isDataType )
|
||||
{
|
||||
// Is this a template type?
|
||||
tempString.Assign(&script->code[t2.pos], t2.length);
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) )
|
||||
isTemplateType = true;
|
||||
}
|
||||
|
||||
// Rewind so the real parsing can be done, after deciding what to parse
|
||||
RewindTo(&t1);
|
||||
|
||||
// Check if this is a construct call
|
||||
if( isDataType && (t.type == ttOpenParanthesis || // type()
|
||||
t.type == ttOpenBracket) ) // type[]()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( isTemplateType && t.type == ttLessThan ) // type<t>()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( IsFunctionCall() )
|
||||
node->AddChildLast(ParseFunctionCall());
|
||||
else
|
||||
node->AddChildLast(ParseVariableAccess());
|
||||
{
|
||||
// Determine the last identifier in order to check if it is a type
|
||||
sToken t;
|
||||
if( t1.type == ttScope ) t = t2; else t = t1;
|
||||
RewindTo(&t);
|
||||
GetToken(&t2);
|
||||
while( t.type == ttIdentifier )
|
||||
{
|
||||
t2 = t;
|
||||
GetToken(&t);
|
||||
if( t.type == ttScope )
|
||||
GetToken(&t);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
bool isDataType = IsDataType(t2);
|
||||
bool isTemplateType = false;
|
||||
if( isDataType )
|
||||
{
|
||||
// Is this a template type?
|
||||
tempString.Assign(&script->code[t2.pos], t2.length);
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) )
|
||||
isTemplateType = true;
|
||||
}
|
||||
|
||||
GetToken(&t2);
|
||||
|
||||
// Rewind so the real parsing can be done, after deciding what to parse
|
||||
RewindTo(&t1);
|
||||
|
||||
// Check if this is a construct call
|
||||
if( isDataType && (t.type == ttOpenParanthesis || // type()
|
||||
(t.type == ttOpenBracket && t2.type == ttCloseBracket)) ) // type[]()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( isTemplateType && t.type == ttLessThan ) // type<t>()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( IsFunctionCall() )
|
||||
node->AddChildLast(ParseFunctionCall());
|
||||
else
|
||||
node->AddChildLast(ParseVariableAccess());
|
||||
}
|
||||
}
|
||||
else if( t1.type == ttCast )
|
||||
node->AddChildLast(ParseCast());
|
||||
@ -1355,6 +1376,83 @@ asCScriptNode *asCParser::ParseConstant()
|
||||
return node;
|
||||
}
|
||||
|
||||
bool asCParser::IsLambda()
|
||||
{
|
||||
bool isLambda = false;
|
||||
sToken t;
|
||||
GetToken(&t);
|
||||
if( t.type == ttIdentifier && IdentifierIs(t, FUNCTION_TOKEN) )
|
||||
{
|
||||
sToken t2;
|
||||
GetToken(&t2);
|
||||
if( t2.type == ttOpenParanthesis )
|
||||
{
|
||||
// Skip until )
|
||||
while( t2.type != ttCloseParanthesis && t2.type != ttEnd )
|
||||
GetToken(&t2);
|
||||
|
||||
// The next token must be a {
|
||||
GetToken(&t2);
|
||||
if( t2.type == ttStartStatementBlock )
|
||||
isLambda = true;
|
||||
}
|
||||
}
|
||||
|
||||
RewindTo(&t);
|
||||
return isLambda;
|
||||
}
|
||||
|
||||
// BNF: LAMBDA ::= 'function' '(' [IDENTIFIER {',' IDENTIFIER}] ')' STATBLOCK
|
||||
asCScriptNode *asCParser::ParseLambda()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snFunction);
|
||||
if( node == 0 ) return 0;
|
||||
|
||||
sToken t;
|
||||
GetToken(&t);
|
||||
|
||||
if( t.type != ttIdentifier || !IdentifierIs(t, FUNCTION_TOKEN) )
|
||||
{
|
||||
Error(ExpectedToken("function"), &t);
|
||||
return node;
|
||||
}
|
||||
|
||||
GetToken(&t);
|
||||
if( t.type != ttOpenParanthesis )
|
||||
{
|
||||
Error(ExpectedToken("("), &t);
|
||||
return node;
|
||||
}
|
||||
|
||||
GetToken(&t);
|
||||
if( t.type == ttIdentifier )
|
||||
{
|
||||
RewindTo(&t);
|
||||
node->AddChildLast(ParseIdentifier());
|
||||
|
||||
GetToken(&t);
|
||||
while( t.type == ttListSeparator )
|
||||
{
|
||||
node->AddChildLast(ParseIdentifier());
|
||||
if( isSyntaxError ) return node;
|
||||
|
||||
GetToken(&t);
|
||||
}
|
||||
}
|
||||
|
||||
if( t.type != ttCloseParanthesis )
|
||||
{
|
||||
Error(ExpectedToken(")"), &t);
|
||||
return node;
|
||||
}
|
||||
|
||||
// We should just find the end of the statement block here. The statements
|
||||
// will be parsed on request by the compiler once it starts the compilation.
|
||||
node->AddChildLast(SuperficiallyParseStatementBlock());
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
asCScriptNode *asCParser::ParseStringConstant()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snConstant);
|
||||
@ -1618,7 +1716,7 @@ asCScriptNode *asCParser::ParseCondition()
|
||||
return node;
|
||||
}
|
||||
|
||||
// BNF: EXPR ::= (TYPE '=' INILIST) | (EXPRTERM {EXPROP EXPRTERM})
|
||||
// BNF: EXPR ::= (TYPE '=' INITLIST) | (EXPRTERM {EXPROP EXPRTERM})
|
||||
asCScriptNode *asCParser::ParseExpression()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snExpression);
|
||||
@ -2459,7 +2557,22 @@ bool asCParser::IsVirtualPropertyDecl()
|
||||
// as it may wrongly identify the statement as a non-declaration if the user typed
|
||||
// the name incorrectly. The real type is validated in ParseDeclaration where a
|
||||
// proper error message can be given.
|
||||
if( !IsRealType(t1.type) && t1.type != ttIdentifier )
|
||||
if( t1.type == ttScope )
|
||||
GetToken(&t1);
|
||||
|
||||
if( t1.type == ttIdentifier )
|
||||
{
|
||||
sToken t2;
|
||||
GetToken(&t2);
|
||||
while( t1.type == ttIdentifier && t2.type == ttScope )
|
||||
{
|
||||
GetToken(&t1);
|
||||
GetToken(&t2);
|
||||
}
|
||||
|
||||
RewindTo(&t2);
|
||||
}
|
||||
else if( !IsRealType(t1.type) )
|
||||
{
|
||||
RewindTo(&t);
|
||||
return false;
|
||||
@ -3201,61 +3314,37 @@ asCScriptNode *asCParser::SuperficiallyParseVarInit()
|
||||
if( t.type == ttAssignment )
|
||||
{
|
||||
GetToken(&t);
|
||||
if( t.type == ttStartStatementBlock )
|
||||
sToken start = t;
|
||||
|
||||
// Find the end of the expression
|
||||
int indentParan = 0;
|
||||
int indentBrace = 0;
|
||||
while( indentParan || indentBrace || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) )
|
||||
{
|
||||
sToken start = t;
|
||||
|
||||
// Find the end of the initialization list
|
||||
int indent = 1;
|
||||
while( indent )
|
||||
if( t.type == ttOpenParanthesis )
|
||||
indentParan++;
|
||||
else if( t.type == ttCloseParanthesis )
|
||||
indentParan--;
|
||||
else if( t.type == ttStartStatementBlock )
|
||||
indentBrace++;
|
||||
else if( t.type == ttEndStatementBlock )
|
||||
indentBrace--;
|
||||
else if( t.type == ttNonTerminatedStringConstant )
|
||||
{
|
||||
GetToken(&t);
|
||||
if( t.type == ttStartStatementBlock )
|
||||
indent++;
|
||||
else if( t.type == ttEndStatementBlock )
|
||||
indent--;
|
||||
else if( t.type == ttNonTerminatedStringConstant )
|
||||
{
|
||||
Error(TXT_NONTERMINATED_STRING, &t);
|
||||
break;
|
||||
}
|
||||
else if( t.type == ttEnd )
|
||||
{
|
||||
Error(TXT_UNEXPECTED_END_OF_FILE, &t);
|
||||
Info(TXT_WHILE_PARSING_INIT_LIST, &start);
|
||||
break;
|
||||
}
|
||||
Error(TXT_NONTERMINATED_STRING, &t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sToken start = t;
|
||||
|
||||
// Find the end of the expression
|
||||
int indent = 0;
|
||||
while( indent || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) )
|
||||
else if( t.type == ttEnd )
|
||||
{
|
||||
if( t.type == ttOpenParanthesis )
|
||||
indent++;
|
||||
else if( t.type == ttCloseParanthesis )
|
||||
indent--;
|
||||
else if( t.type == ttNonTerminatedStringConstant )
|
||||
{
|
||||
Error(TXT_NONTERMINATED_STRING, &t);
|
||||
break;
|
||||
}
|
||||
else if( t.type == ttEnd )
|
||||
{
|
||||
Error(TXT_UNEXPECTED_END_OF_FILE, &t);
|
||||
Info(TXT_WHILE_PARSING_EXPRESSION, &start);
|
||||
break;
|
||||
}
|
||||
GetToken(&t);
|
||||
Error(TXT_UNEXPECTED_END_OF_FILE, &t);
|
||||
Info(TXT_WHILE_PARSING_EXPRESSION, &start);
|
||||
break;
|
||||
}
|
||||
|
||||
// Rewind so that the next token read is the list separator, end statement, or end statement block
|
||||
RewindTo(&t);
|
||||
GetToken(&t);
|
||||
}
|
||||
|
||||
// Rewind so that the next token read is the list separator, end statement, or end statement block
|
||||
RewindTo(&t);
|
||||
}
|
||||
else if( t.type == ttOpenParanthesis )
|
||||
{
|
||||
@ -3872,7 +3961,7 @@ asCScriptNode *asCParser::ParseIf()
|
||||
return node;
|
||||
}
|
||||
|
||||
// BNF: FOR ::= 'for' '(' (VAR | EXPRSTAT) EXPRSTAT [ASSIGN] ')' STATEMENT
|
||||
// BNF: FOR ::= 'for' '(' (VAR | EXPRSTAT) EXPRSTAT [ASSIGN {',' ASSIGN}] ')' STATEMENT
|
||||
asCScriptNode *asCParser::ParseFor()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snFor);
|
||||
@ -3911,18 +4000,27 @@ asCScriptNode *asCParser::ParseFor()
|
||||
{
|
||||
RewindTo(&t);
|
||||
|
||||
asCScriptNode *n = CreateNode(snExpressionStatement);
|
||||
if( n == 0 ) return 0;
|
||||
node->AddChildLast(n);
|
||||
n->AddChildLast(ParseAssignment());
|
||||
if( isSyntaxError ) return node;
|
||||
|
||||
GetToken(&t);
|
||||
if( t.type != ttCloseParanthesis )
|
||||
// Parse N increment statements separated by ,
|
||||
for(;;)
|
||||
{
|
||||
Error(ExpectedToken(")"), &t);
|
||||
Error(InsteadFound(t), &t);
|
||||
return node;
|
||||
asCScriptNode *n = CreateNode(snExpressionStatement);
|
||||
if( n == 0 ) return 0;
|
||||
node->AddChildLast(n);
|
||||
n->AddChildLast(ParseAssignment());
|
||||
if( isSyntaxError ) return node;
|
||||
|
||||
GetToken(&t);
|
||||
if( t.type == ttListSeparator )
|
||||
continue;
|
||||
else if( t.type == ttCloseParanthesis )
|
||||
break;
|
||||
else
|
||||
{
|
||||
const char *tokens[] = {",", ")"};
|
||||
Error(ExpectedOneOf(tokens, 2), &t);
|
||||
Error(InsteadFound(t), &t);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -133,6 +133,8 @@ protected:
|
||||
bool IsVarDecl();
|
||||
bool IsVirtualPropertyDecl();
|
||||
bool IsFuncDecl(bool isMethod);
|
||||
bool IsLambda();
|
||||
bool IsFunctionCall();
|
||||
|
||||
// Expressions
|
||||
asCScriptNode *ParseAssignment();
|
||||
@ -151,13 +153,13 @@ protected:
|
||||
asCScriptNode *ParseCast();
|
||||
asCScriptNode *ParseConstant();
|
||||
asCScriptNode *ParseStringConstant();
|
||||
asCScriptNode *ParseLambda();
|
||||
|
||||
bool IsConstant(int tokenType);
|
||||
bool IsOperator(int tokenType);
|
||||
bool IsPreOperator(int tokenType);
|
||||
bool IsPostOperator(int tokenType);
|
||||
bool IsAssignOperator(int tokenType);
|
||||
bool IsFunctionCall();
|
||||
|
||||
bool CheckTemplateType(sToken &t);
|
||||
#endif
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "as_bytecode.h"
|
||||
#include "as_scriptobject.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_debug.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
@ -65,6 +66,8 @@ void asCReader::ReadData(void *data, asUINT size)
|
||||
|
||||
int asCReader::Read(bool *wasDebugInfoStripped)
|
||||
{
|
||||
TimeIt("asCReader::Read");
|
||||
|
||||
// Before starting the load, make sure that
|
||||
// any existing resources have been freed
|
||||
module->InternalReset();
|
||||
@ -124,6 +127,8 @@ int asCReader::Error(const char *msg)
|
||||
|
||||
int asCReader::ReadInner()
|
||||
{
|
||||
TimeIt("asCReader::ReadInner");
|
||||
|
||||
// This function will load each entity one by one from the stream.
|
||||
// If any error occurs, it will return to the caller who is
|
||||
// responsible for cleaning up the partially loaded entities.
|
||||
@ -258,31 +263,38 @@ int asCReader::ReadInner()
|
||||
asCScriptFunction *func = ReadFunction(isNew, false, true);
|
||||
if( func )
|
||||
{
|
||||
func->module = module;
|
||||
module->funcDefs.PushLast(func);
|
||||
engine->funcDefs.PushLast(func);
|
||||
|
||||
// TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module
|
||||
// Check if there is another identical funcdef from another module and if so reuse that instead
|
||||
for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
|
||||
if( func->isShared )
|
||||
{
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
|
||||
if( f2->name == func->name &&
|
||||
f2->nameSpace == func->nameSpace &&
|
||||
f2->IsSignatureExceptNameEqual(func) )
|
||||
for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
|
||||
{
|
||||
// Replace our funcdef for the existing one
|
||||
module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
|
||||
f2->AddRefInternal();
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
if( !f2->isShared )
|
||||
continue;
|
||||
|
||||
savedFunctions[savedFunctions.IndexOf(func)] = f2;
|
||||
if( f2->name == func->name &&
|
||||
f2->nameSpace == func->nameSpace &&
|
||||
f2->IsSignatureExceptNameEqual(func) )
|
||||
{
|
||||
// Replace our funcdef for the existing one
|
||||
module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
|
||||
f2->AddRefInternal();
|
||||
|
||||
func->ReleaseInternal();
|
||||
break;
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
|
||||
savedFunctions[savedFunctions.IndexOf(func)] = f2;
|
||||
|
||||
func->ReleaseInternal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -549,6 +561,8 @@ int asCReader::ReadInner()
|
||||
|
||||
void asCReader::ReadUsedStringConstants()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedStringConstants");
|
||||
|
||||
asCString str;
|
||||
|
||||
asUINT count;
|
||||
@ -563,6 +577,8 @@ void asCReader::ReadUsedStringConstants()
|
||||
|
||||
void asCReader::ReadUsedFunctions()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedFunctions");
|
||||
|
||||
asUINT count;
|
||||
count = ReadEncodedUInt();
|
||||
usedFunctions.SetLength(count);
|
||||
@ -606,25 +622,44 @@ void asCReader::ReadUsedFunctions()
|
||||
for( asUINT i = 0; i < module->bindInformations.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = module->bindInformations[i]->importedFunctionSignature;
|
||||
if( !func.IsSignatureEqual(f) ||
|
||||
func.objectType != f->objectType ||
|
||||
if( func.objectType != f->objectType ||
|
||||
func.funcType != f->funcType ||
|
||||
func.nameSpace != f->nameSpace )
|
||||
func.nameSpace != f->nameSpace ||
|
||||
!func.IsSignatureEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( func.funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
const asCArray<asCScriptFunction *> &funcs = module->funcDefs;
|
||||
for( asUINT i = 0; i < funcs.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = funcs[i];
|
||||
if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
// Funcdefs are always global so there is no need to compare object type
|
||||
asASSERT( f->objectType == 0 );
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: optimize: Global functions should be searched for in module->globalFunctions
|
||||
// TODO: optimize: funcdefs should be searched for in module->funcDefs
|
||||
// TODO: optimize: object methods should be searched for directly in the object type
|
||||
for( asUINT i = 0; i < module->scriptFunctions.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = module->scriptFunctions[i];
|
||||
if( !func.IsSignatureEqual(f) ||
|
||||
func.objectType != f->objectType ||
|
||||
if( func.objectType != f->objectType ||
|
||||
func.funcType != f->funcType ||
|
||||
func.nameSpace != f->nameSpace )
|
||||
func.nameSpace != f->nameSpace ||
|
||||
!func.IsSignatureEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
@ -634,17 +669,157 @@ void asCReader::ReadUsedFunctions()
|
||||
}
|
||||
else
|
||||
{
|
||||
for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ )
|
||||
if( func.funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[i];
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureEqual(f) ||
|
||||
func.objectType != f->objectType ||
|
||||
func.nameSpace != f->nameSpace )
|
||||
continue;
|
||||
// This is a funcdef (registered or shared)
|
||||
const asCArray<asCScriptFunction *> &funcs = engine->funcDefs;
|
||||
for( asUINT i = 0; i < funcs.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = funcs[i];
|
||||
if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
// Funcdefs are always global so there is no need to compare object type
|
||||
asASSERT( f->objectType == 0 );
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( func.name[0] == '$' )
|
||||
{
|
||||
// This is a special function
|
||||
|
||||
// Check for string factory
|
||||
if( func.name == "$str" && engine->stringFactory &&
|
||||
func.IsSignatureExceptNameAndObjectTypeEqual(engine->stringFactory) )
|
||||
usedFunctions[n] = engine->stringFactory;
|
||||
else if( func.name == "$beh0" && func.objectType )
|
||||
{
|
||||
// This is a class constructor, so we can search directly in the object type's constructors
|
||||
for( asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]];
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( func.name == "$fact" || func.name == "$beh3" )
|
||||
{
|
||||
// This is a factory (or stub), so look for the function in the return type's factories
|
||||
asCObjectType *objType = func.returnType.GetObjectType();
|
||||
if( objType )
|
||||
{
|
||||
for( asUINT i = 0; i < objType->beh.factories.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[objType->beh.factories[i]];
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( func.name == "$list" )
|
||||
{
|
||||
// listFactory is used for both factory is global and returns a handle and constructor that is a method
|
||||
asCObjectType *objType = func.objectType ? func.objectType : func.returnType.GetObjectType();
|
||||
if( objType )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory];
|
||||
if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
usedFunctions[n] = f;
|
||||
}
|
||||
}
|
||||
else if( func.name == "$beh2" )
|
||||
{
|
||||
// This is a destructor, so check the object type's destructor
|
||||
asCObjectType *objType = func.objectType;
|
||||
if( objType )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[objType->beh.destruct];
|
||||
if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
usedFunctions[n] = f;
|
||||
}
|
||||
}
|
||||
else if( func.name == "$beh4" )
|
||||
{
|
||||
// This is a list factory, so check the return type's list factory
|
||||
asCObjectType *objType = func.returnType.GetObjectType();
|
||||
if( objType )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory];
|
||||
if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
usedFunctions[n] = f;
|
||||
}
|
||||
}
|
||||
else if( func.name == "$dlgte" )
|
||||
{
|
||||
// This is the delegate factory
|
||||
asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY);
|
||||
asASSERT( f && func.IsSignatureEqual(f) );
|
||||
usedFunctions[n] = f;
|
||||
}
|
||||
}
|
||||
else if( func.objectType == 0 )
|
||||
{
|
||||
// This is a global function
|
||||
const asCArray<asUINT> &funcs = engine->registeredGlobalFuncs.GetIndexes(func.nameSpace, func.name);
|
||||
for( asUINT i = 0; i < funcs.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->registeredGlobalFuncs.Get(funcs[i]);
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( func.objectType )
|
||||
{
|
||||
// It is a class member, so we can search directly in the object type's members
|
||||
// TODO: virtual function is different that implemented method
|
||||
for( asUINT i = 0; i < func.objectType->methods.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[func.objectType->methods[i]];
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( usedFunctions[n] == 0 )
|
||||
{
|
||||
// TODO: clean up: This part of the code should never happen. All functions should
|
||||
// be found in the above logic. The only valid reason to come here
|
||||
// is if the bytecode is wrong and the function doesn't exist anyway.
|
||||
// This loop is kept temporarily until we can be certain all scenarios
|
||||
// are covered.
|
||||
for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[i];
|
||||
if( f == 0 ||
|
||||
func.objectType != f->objectType ||
|
||||
func.nameSpace != f->nameSpace ||
|
||||
!func.IsSignatureEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
|
||||
// No function is expected to be found
|
||||
asASSERT(usedFunctions[n] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -973,6 +1148,13 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
|
||||
{
|
||||
func->vfTableIdx = ReadEncodedUInt();
|
||||
}
|
||||
else if( func->funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
asBYTE bits;
|
||||
ReadData(&bits, 1);
|
||||
if( bits )
|
||||
func->isShared = true;
|
||||
}
|
||||
|
||||
if( addToModule )
|
||||
{
|
||||
@ -1520,28 +1702,25 @@ asQWORD asCReader::ReadEncodedUInt64()
|
||||
|
||||
void asCReader::ReadString(asCString* str)
|
||||
{
|
||||
char b;
|
||||
ReadData(&b, 1);
|
||||
if( b == '\0' )
|
||||
asUINT len = ReadEncodedUInt();
|
||||
if( len & 1 )
|
||||
{
|
||||
str->SetLength(0);
|
||||
asUINT idx = len/2;
|
||||
if( idx < savedStrings.GetLength() )
|
||||
*str = savedStrings[idx];
|
||||
else
|
||||
Error(TXT_INVALID_BYTECODE_d);
|
||||
}
|
||||
else if( b == 'n' )
|
||||
else if( len > 0 )
|
||||
{
|
||||
asUINT len = ReadEncodedUInt();
|
||||
len /= 2;
|
||||
str->SetLength(len);
|
||||
stream->Read(str->AddressOf(), len);
|
||||
|
||||
savedStrings.PushLast(*str);
|
||||
}
|
||||
else
|
||||
{
|
||||
asUINT n = ReadEncodedUInt();
|
||||
if( n < savedStrings.GetLength() )
|
||||
*str = savedStrings[n];
|
||||
else
|
||||
Error(TXT_INVALID_BYTECODE_d);
|
||||
}
|
||||
str->SetLength(0);
|
||||
}
|
||||
|
||||
void asCReader::ReadGlobalProperty()
|
||||
@ -1625,7 +1804,7 @@ void asCReader::ReadDataType(asCDataType *dt)
|
||||
ReadData(&bits, 1);
|
||||
|
||||
asCScriptFunction *funcDef = 0;
|
||||
if( tokenType == ttIdentifier && objType && objType->name == "_builtin_function_" )
|
||||
if( tokenType == ttIdentifier && objType && objType->name == "$func" )
|
||||
{
|
||||
asCScriptFunction func(engine, module, asFUNC_DUMMY);
|
||||
ReadFunctionSignature(&func);
|
||||
@ -1790,7 +1969,7 @@ asCObjectType* asCReader::ReadObjectType()
|
||||
ReadString(&ns);
|
||||
asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
|
||||
|
||||
if( typeName.GetLength() && typeName != "_builtin_object_" && typeName != "_builtin_function_" )
|
||||
if( typeName.GetLength() && typeName != "$obj" && typeName != "$func" )
|
||||
{
|
||||
// Find the object type
|
||||
ot = module->GetObjectType(typeName.AddressOf(), nameSpace);
|
||||
@ -1806,11 +1985,11 @@ asCObjectType* asCReader::ReadObjectType()
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if( typeName == "_builtin_object_" )
|
||||
else if( typeName == "$obj" )
|
||||
{
|
||||
ot = &engine->scriptTypeBehaviours;
|
||||
}
|
||||
else if( typeName == "_builtin_function_" )
|
||||
else if( typeName == "$func" )
|
||||
{
|
||||
ot = &engine->functionBehaviours;
|
||||
}
|
||||
@ -2073,6 +2252,8 @@ void asCReader::ReadByteCode(asCScriptFunction *func)
|
||||
|
||||
void asCReader::ReadUsedTypeIds()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedTypeIds");
|
||||
|
||||
asUINT count = ReadEncodedUInt();
|
||||
usedTypeIds.Allocate(count, false);
|
||||
for( asUINT n = 0; n < count; n++ )
|
||||
@ -2085,6 +2266,8 @@ void asCReader::ReadUsedTypeIds()
|
||||
|
||||
void asCReader::ReadUsedGlobalProps()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedGlobalProps");
|
||||
|
||||
int c = ReadEncodedUInt();
|
||||
|
||||
usedGlobalProperties.Allocate(c, false);
|
||||
@ -2124,6 +2307,8 @@ void asCReader::ReadUsedGlobalProps()
|
||||
|
||||
void asCReader::ReadUsedObjectProps()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedObjectProps");
|
||||
|
||||
asUINT c = ReadEncodedUInt();
|
||||
|
||||
usedObjectProperties.SetLength(c);
|
||||
@ -2293,7 +2478,8 @@ void asCReader::TranslateFunction(asCScriptFunction *func)
|
||||
}
|
||||
else if( c == asBC_CALL ||
|
||||
c == asBC_CALLINTF ||
|
||||
c == asBC_CALLSYS )
|
||||
c == asBC_CALLSYS ||
|
||||
c == asBC_Thiscall1 )
|
||||
{
|
||||
// Translate the index to the func id
|
||||
int *fid = (int*)&bc[n+1];
|
||||
@ -2800,7 +2986,8 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func)
|
||||
{
|
||||
// Determine the true delta from the instruction arguments
|
||||
if( bc == asBC_CALL ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_Thiscall1 ||
|
||||
bc == asBC_CALLBND ||
|
||||
bc == asBC_ALLOC ||
|
||||
bc == asBC_CALLINTF ||
|
||||
@ -3030,6 +3217,7 @@ asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD
|
||||
|
||||
if( bc == asBC_CALL ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_Thiscall1 ||
|
||||
bc == asBC_CALLINTF )
|
||||
{
|
||||
// Find the function from the function id in bytecode
|
||||
@ -3085,11 +3273,13 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
|
||||
// Find out which function that will be called
|
||||
asCScriptFunction *calledFunc = 0;
|
||||
int stackDelta = 0;
|
||||
for( asUINT n = programPos; func->scriptData->byteCode.GetLength(); )
|
||||
{
|
||||
asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
|
||||
if( bc == asBC_CALL ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_Thiscall1 ||
|
||||
bc == asBC_CALLINTF ||
|
||||
bc == asBC_ALLOC ||
|
||||
bc == asBC_CALLBND ||
|
||||
@ -3106,6 +3296,10 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
return offset - (1 - AS_PTR_SIZE);
|
||||
}
|
||||
|
||||
// Keep track of the stack size between the
|
||||
// instruction that needs to be adjusted and the call
|
||||
stackDelta += asBCInfo[bc].stackInc;
|
||||
|
||||
n += asBCTypeSize[asBCInfo[bc].type];
|
||||
}
|
||||
|
||||
@ -3118,16 +3312,30 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
// Count the number of pointers pushed on the stack above the
|
||||
// current offset, and then adjust the offset accordingly
|
||||
asUINT numPtrs = 0;
|
||||
int currOffset = 0;
|
||||
int currOffset = -stackDelta;
|
||||
if( offset > currOffset && calledFunc->GetObjectType() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset++;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
#if AS_PTR_SIZE == 2
|
||||
// For 64bit platforms it is necessary to increment the currOffset by one more
|
||||
// DWORD since the stackDelta was counting the full 64bit size of the pointer
|
||||
else if( stackDelta )
|
||||
currOffset++;
|
||||
#endif
|
||||
}
|
||||
if( offset > currOffset && calledFunc->DoesReturnOnStack() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset++;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
#if AS_PTR_SIZE == 2
|
||||
// For 64bit platforms it is necessary to increment the currOffset by one more
|
||||
// DWORD since the stackDelta was counting the full 64bit size of the pointer
|
||||
else if( stackDelta )
|
||||
currOffset++;
|
||||
#endif
|
||||
}
|
||||
for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
|
||||
{
|
||||
@ -3136,8 +3344,15 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
if( !calledFunc->parameterTypes[p].IsPrimitive() ||
|
||||
calledFunc->parameterTypes[p].IsReference() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset++;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
#if AS_PTR_SIZE == 2
|
||||
// For 64bit platforms it is necessary to increment the currOffset by one more
|
||||
// DWORD since the stackDelta was counting the full 64bit size of the pointer
|
||||
else if( stackDelta )
|
||||
currOffset++;
|
||||
#endif
|
||||
|
||||
// The variable arg ? has an additiona 32bit integer with the typeid
|
||||
if( calledFunc->parameterTypes[p].IsAnyType() )
|
||||
@ -3197,6 +3412,8 @@ void asCWriter::WriteData(const void *data, asUINT size)
|
||||
|
||||
int asCWriter::Write()
|
||||
{
|
||||
TimeIt("asCWriter::Write");
|
||||
|
||||
unsigned long i, count;
|
||||
|
||||
// Store everything in the same order that the builder parses scripts
|
||||
@ -3207,101 +3424,149 @@ int asCWriter::Write()
|
||||
WriteData(&stripDebugInfo, sizeof(stripDebugInfo));
|
||||
|
||||
// Store enums
|
||||
count = (asUINT)module->enumTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
WriteObjectTypeDeclaration(module->enumTypes[i], 1);
|
||||
WriteObjectTypeDeclaration(module->enumTypes[i], 2);
|
||||
TimeIt("store enums");
|
||||
|
||||
count = (asUINT)module->enumTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
WriteObjectTypeDeclaration(module->enumTypes[i], 1);
|
||||
WriteObjectTypeDeclaration(module->enumTypes[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Store type declarations first
|
||||
count = (asUINT)module->classTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
// Store only the name of the class/interface types
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 1);
|
||||
TimeIt("type declarations");
|
||||
|
||||
count = (asUINT)module->classTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
// Store only the name of the class/interface types
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Store func defs
|
||||
count = (asUINT)module->funcDefs.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
WriteFunction(module->funcDefs[i]);
|
||||
{
|
||||
TimeIt("func defs");
|
||||
|
||||
count = (asUINT)module->funcDefs.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
WriteFunction(module->funcDefs[i]);
|
||||
}
|
||||
|
||||
// Now store all interface methods
|
||||
count = (asUINT)module->classTypes.GetLength();
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
if( module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 2);
|
||||
TimeIt("interface methods");
|
||||
|
||||
count = (asUINT)module->classTypes.GetLength();
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
if( module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Then store the class methods and behaviours
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
if( !module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 2);
|
||||
TimeIt("class methods and behaviours");
|
||||
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
if( !module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Then store the class properties
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
if( !module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 3);
|
||||
TimeIt("class properties");
|
||||
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
if( !module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Store typedefs
|
||||
count = (asUINT)module->typeDefs.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
WriteObjectTypeDeclaration(module->typeDefs[i], 1);
|
||||
WriteObjectTypeDeclaration(module->typeDefs[i], 2);
|
||||
TimeIt("type defs");
|
||||
|
||||
count = (asUINT)module->typeDefs.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
WriteObjectTypeDeclaration(module->typeDefs[i], 1);
|
||||
WriteObjectTypeDeclaration(module->typeDefs[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
// scriptGlobals[]
|
||||
count = (asUINT)module->scriptGlobals.GetSize();
|
||||
WriteEncodedInt64(count);
|
||||
asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
|
||||
for( ; it; it++ )
|
||||
WriteGlobalProperty(*it);
|
||||
{
|
||||
TimeIt("script globals");
|
||||
|
||||
count = (asUINT)module->scriptGlobals.GetSize();
|
||||
WriteEncodedInt64(count);
|
||||
asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
|
||||
for( ; it; it++ )
|
||||
WriteGlobalProperty(*it);
|
||||
}
|
||||
|
||||
// scriptFunctions[]
|
||||
count = 0;
|
||||
for( i = 0; i < module->scriptFunctions.GetLength(); i++ )
|
||||
if( module->scriptFunctions[i]->objectType == 0 )
|
||||
count++;
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < module->scriptFunctions.GetLength(); ++i )
|
||||
if( module->scriptFunctions[i]->objectType == 0 )
|
||||
WriteFunction(module->scriptFunctions[i]);
|
||||
{
|
||||
TimeIt("scriptFunctions");
|
||||
|
||||
count = 0;
|
||||
for( i = 0; i < module->scriptFunctions.GetLength(); i++ )
|
||||
if( module->scriptFunctions[i]->objectType == 0 )
|
||||
count++;
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < module->scriptFunctions.GetLength(); ++i )
|
||||
if( module->scriptFunctions[i]->objectType == 0 )
|
||||
WriteFunction(module->scriptFunctions[i]);
|
||||
}
|
||||
|
||||
// globalFunctions[]
|
||||
count = (int)module->globalFunctions.GetSize();
|
||||
asCSymbolTable<asCScriptFunction>::iterator funcIt = module->globalFunctions.List();
|
||||
WriteEncodedInt64(count);
|
||||
while( funcIt )
|
||||
{
|
||||
WriteFunction(*funcIt);
|
||||
funcIt++;
|
||||
TimeIt("globalFunctions");
|
||||
|
||||
count = (int)module->globalFunctions.GetSize();
|
||||
asCSymbolTable<asCScriptFunction>::iterator funcIt = module->globalFunctions.List();
|
||||
WriteEncodedInt64(count);
|
||||
while( funcIt )
|
||||
{
|
||||
WriteFunction(*funcIt);
|
||||
funcIt++;
|
||||
}
|
||||
}
|
||||
|
||||
// bindInformations[]
|
||||
count = (asUINT)module->bindInformations.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
WriteFunction(module->bindInformations[i]->importedFunctionSignature);
|
||||
WriteString(&module->bindInformations[i]->importFromModule);
|
||||
TimeIt("bindInformations");
|
||||
|
||||
count = (asUINT)module->bindInformations.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
WriteFunction(module->bindInformations[i]->importedFunctionSignature);
|
||||
WriteString(&module->bindInformations[i]->importFromModule);
|
||||
}
|
||||
}
|
||||
|
||||
// usedTypes[]
|
||||
count = (asUINT)usedTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; ++i )
|
||||
WriteObjectType(usedTypes[i]);
|
||||
{
|
||||
TimeIt("usedTypes");
|
||||
|
||||
count = (asUINT)usedTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; ++i )
|
||||
WriteObjectType(usedTypes[i]);
|
||||
}
|
||||
|
||||
// usedTypeIds[]
|
||||
WriteUsedTypeIds();
|
||||
@ -3335,6 +3600,8 @@ int asCWriter::FindStringConstantIndex(int id)
|
||||
|
||||
void asCWriter::WriteUsedStringConstants()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedStringConstants");
|
||||
|
||||
asUINT count = (asUINT)usedStringConstants.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( asUINT i = 0; i < count; ++i )
|
||||
@ -3343,6 +3610,8 @@ void asCWriter::WriteUsedStringConstants()
|
||||
|
||||
void asCWriter::WriteUsedFunctions()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedFunctions");
|
||||
|
||||
asUINT count = (asUINT)usedFunctions.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
|
||||
@ -3572,6 +3841,12 @@ void asCWriter::WriteFunction(asCScriptFunction* func)
|
||||
// TODO: Do we really need to store this? It can probably be reconstructed by the reader
|
||||
WriteEncodedInt64(func->vfTableIdx);
|
||||
}
|
||||
else if( func->funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
char bits = 0;
|
||||
bits += func->isShared ? 1 : 0;
|
||||
WriteData(&bits,1);
|
||||
}
|
||||
}
|
||||
|
||||
void asCWriter::WriteObjectTypeDeclaration(asCObjectType *ot, int phase)
|
||||
@ -3755,39 +4030,28 @@ void asCWriter::WriteEncodedInt64(asINT64 i)
|
||||
|
||||
void asCWriter::WriteString(asCString* str)
|
||||
{
|
||||
// TODO: All strings should be stored in a separate section, and when
|
||||
// they are used an offset into that section should be stored.
|
||||
// This will make it unnecessary to store the extra byte to
|
||||
// identify new versus old strings.
|
||||
|
||||
if( str->GetLength() == 0 )
|
||||
{
|
||||
char z = '\0';
|
||||
WriteData(&z, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// First check if the string hasn't been saved already
|
||||
asSMapNode<asCStringPointer, int> *cursor = 0;
|
||||
if (stringToIdMap.MoveTo(&cursor, asCStringPointer(str)))
|
||||
{
|
||||
// Save a reference to the existing string
|
||||
char b = 'r';
|
||||
WriteData(&b, 1);
|
||||
WriteEncodedInt64(cursor->value);
|
||||
// The lowest bit is set to 1 to indicate a reference
|
||||
WriteEncodedInt64(cursor->value*2+1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save a new string
|
||||
char b = 'n';
|
||||
WriteData(&b, 1);
|
||||
|
||||
// The lowest bit is set to 0 to indicate a new string
|
||||
asUINT len = (asUINT)str->GetLength();
|
||||
WriteEncodedInt64(len);
|
||||
stream->Write(str->AddressOf(), (asUINT)len);
|
||||
WriteEncodedInt64(len*2);
|
||||
|
||||
savedStrings.PushLast(*str);
|
||||
stringToIdMap.Insert(asCStringPointer(str), int(savedStrings.GetLength()) - 1);
|
||||
if( len > 0 )
|
||||
{
|
||||
stream->Write(str->AddressOf(), (asUINT)len);
|
||||
|
||||
savedStrings.PushLast(*str);
|
||||
stringToIdMap.Insert(asCStringPointer(str), int(savedStrings.GetLength()) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop)
|
||||
@ -3851,7 +4115,7 @@ void asCWriter::WriteDataType(const asCDataType *dt)
|
||||
bits.isReadOnly = dt->IsReadOnly();
|
||||
WriteData(&bits, 1);
|
||||
|
||||
if( t == ttIdentifier && dt->GetObjectType()->name == "_builtin_function_" )
|
||||
if( t == ttIdentifier && dt->GetObjectType()->name == "$func" )
|
||||
{
|
||||
WriteFunctionSignature(dt->GetFuncDef());
|
||||
}
|
||||
@ -3883,17 +4147,17 @@ void asCWriter::WriteObjectType(asCObjectType* ot)
|
||||
WriteEncodedInt64(ot->templateSubTypes.GetLength());
|
||||
for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ )
|
||||
{
|
||||
if( ot->templateSubTypes[0].IsObject() || ot->templateSubTypes[0].IsEnumType() )
|
||||
if( ot->templateSubTypes[n].IsObject() || ot->templateSubTypes[n].IsEnumType() )
|
||||
{
|
||||
ch = 's';
|
||||
WriteData(&ch, 1);
|
||||
WriteDataType(&ot->templateSubTypes[0]);
|
||||
WriteDataType(&ot->templateSubTypes[n]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = 't';
|
||||
WriteData(&ch, 1);
|
||||
eTokenType t = ot->templateSubTypes[0].GetTokenType();
|
||||
eTokenType t = ot->templateSubTypes[n].GetTokenType();
|
||||
WriteEncodedInt64(t);
|
||||
}
|
||||
}
|
||||
@ -4053,11 +4317,13 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
|
||||
// Find out which function that will be called
|
||||
asCScriptFunction *calledFunc = 0;
|
||||
int stackDelta = 0;
|
||||
for( asUINT n = programPos; n < func->scriptData->byteCode.GetLength(); )
|
||||
{
|
||||
asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
|
||||
if( bc == asBC_CALL ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_Thiscall1 ||
|
||||
bc == asBC_CALLINTF )
|
||||
{
|
||||
// Find the function from the function id in bytecode
|
||||
@ -4120,6 +4386,10 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
return offset + (1 - AS_PTR_SIZE);
|
||||
}
|
||||
|
||||
// Keep track of the stack size between the
|
||||
// instruction that needs to be adjusted and the call
|
||||
stackDelta += asBCInfo[bc].stackInc;
|
||||
|
||||
n += asBCTypeSize[asBCInfo[bc].type];
|
||||
}
|
||||
|
||||
@ -4128,16 +4398,18 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
// Count the number of pointers pushed on the stack above the
|
||||
// current offset, and then adjust the offset accordingly
|
||||
asUINT numPtrs = 0;
|
||||
int currOffset = 0;
|
||||
int currOffset = -stackDelta;
|
||||
if( offset > currOffset && calledFunc->GetObjectType() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset += AS_PTR_SIZE;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
}
|
||||
if( offset > currOffset && calledFunc->DoesReturnOnStack() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset += AS_PTR_SIZE;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
}
|
||||
for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
|
||||
{
|
||||
@ -4147,8 +4419,9 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
calledFunc->parameterTypes[p].IsReference() )
|
||||
{
|
||||
// objects and references are passed by pointer
|
||||
numPtrs++;
|
||||
currOffset += AS_PTR_SIZE;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
|
||||
// The variable arg ? has an additional 32bit int with the typeid
|
||||
if( calledFunc->parameterTypes[p].IsAnyType() )
|
||||
@ -4262,7 +4535,8 @@ void asCWriter::WriteByteCode(asCScriptFunction *func)
|
||||
}
|
||||
else if( c == asBC_CALL || // DW_ARG
|
||||
c == asBC_CALLINTF || // DW_ARG
|
||||
c == asBC_CALLSYS ) // DW_ARG
|
||||
c == asBC_CALLSYS || // DW_ARG
|
||||
c == asBC_Thiscall1 ) // DW_ARG
|
||||
{
|
||||
// Translate the function id
|
||||
*(int*)(tmp+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmp+1)]);
|
||||
@ -4772,6 +5046,8 @@ void asCWriter::SListAdjuster::SetNextType(int typeId)
|
||||
|
||||
void asCWriter::WriteUsedTypeIds()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedTypeIds");
|
||||
|
||||
asUINT count = (asUINT)usedTypeIds.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( asUINT n = 0; n < count; n++ )
|
||||
@ -4792,6 +5068,8 @@ int asCWriter::FindGlobalPropPtrIndex(void *ptr)
|
||||
|
||||
void asCWriter::WriteUsedGlobalProps()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedGlobalProps");
|
||||
|
||||
int c = (int)usedGlobalProperties.GetLength();
|
||||
WriteEncodedInt64(c);
|
||||
|
||||
@ -4799,32 +5077,12 @@ void asCWriter::WriteUsedGlobalProps()
|
||||
{
|
||||
asPWORD *p = (asPWORD*)usedGlobalProperties[n];
|
||||
|
||||
// First search for the global in the module
|
||||
char moduleProp = 0;
|
||||
// Find the property descriptor from the address
|
||||
asCGlobalProperty *prop = 0;
|
||||
asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
|
||||
for( ; it; it++ )
|
||||
asSMapNode<void*, asCGlobalProperty*> *cursor;
|
||||
if( engine->varAddressMap.MoveTo(&cursor, p) )
|
||||
{
|
||||
if( p == (*it)->GetAddressOfValue() )
|
||||
{
|
||||
prop = (*it);
|
||||
moduleProp = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If it is not in the module, it must be an application registered property
|
||||
if( !prop )
|
||||
{
|
||||
asCSymbolTable<asCGlobalProperty>::iterator it = engine->registeredGlobalProps.List();
|
||||
for( ; it; it++ )
|
||||
{
|
||||
if( it->GetAddressOfValue() == p )
|
||||
{
|
||||
prop = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop = engine->varAddressMap.GetValue(cursor);
|
||||
}
|
||||
|
||||
asASSERT(prop);
|
||||
@ -4835,12 +5093,17 @@ void asCWriter::WriteUsedGlobalProps()
|
||||
WriteDataType(&prop->type);
|
||||
|
||||
// Also store whether the property is a module property or a registered property
|
||||
char moduleProp = 0;
|
||||
if( prop->realAddress == 0 )
|
||||
moduleProp = 1;
|
||||
WriteData(&moduleProp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void asCWriter::WriteUsedObjectProps()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedObjectProps");
|
||||
|
||||
int c = (int)usedObjectProperties.GetLength();
|
||||
WriteEncodedInt64(c);
|
||||
|
||||
|
@ -118,6 +118,9 @@ AS_API const char * asGetLibraryOptions()
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
"WIP_16BYTE_ALIGN "
|
||||
#endif
|
||||
#ifdef AS_BIG_ENDIAN
|
||||
"AS_BIG_ENDIAN "
|
||||
#endif
|
||||
|
||||
// Target system
|
||||
#ifdef AS_WIN
|
||||
@ -584,21 +587,22 @@ asCScriptEngine::asCScriptEngine()
|
||||
// Reserve function id 0 for no function
|
||||
scriptFunctions.PushLast(0);
|
||||
|
||||
// Reserve the first typeIds for the primitive types
|
||||
typeIdSeqNbr = asTYPEID_DOUBLE + 1;
|
||||
|
||||
// Make sure typeId for the built-in primitives are defined according to asETypeIdFlags
|
||||
int id = 0;
|
||||
UNUSED_VAR(id); // It is only used in debug mode
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid, false)); asASSERT( id == asTYPEID_VOID );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool, false)); asASSERT( id == asTYPEID_BOOL );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8, false)); asASSERT( id == asTYPEID_INT8 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16, false)); asASSERT( id == asTYPEID_INT16 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt, false)); asASSERT( id == asTYPEID_INT32 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64, false)); asASSERT( id == asTYPEID_INT64 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8, false)); asASSERT( id == asTYPEID_UINT8 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)); asASSERT( id == asTYPEID_UINT16 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt, false)); asASSERT( id == asTYPEID_UINT32 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)); asASSERT( id == asTYPEID_UINT64 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat, false)); asASSERT( id == asTYPEID_FLOAT );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)); asASSERT( id == asTYPEID_DOUBLE );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid, false)) == asTYPEID_VOID );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool, false)) == asTYPEID_BOOL );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8, false)) == asTYPEID_INT8 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16, false)) == asTYPEID_INT16 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt, false)) == asTYPEID_INT32 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64, false)) == asTYPEID_INT64 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8, false)) == asTYPEID_UINT8 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)) == asTYPEID_UINT16 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt, false)) == asTYPEID_UINT32 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)) == asTYPEID_UINT64 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat, false)) == asTYPEID_FLOAT );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)) == asTYPEID_DOUBLE );
|
||||
|
||||
defaultArrayObjectType = 0;
|
||||
|
||||
@ -608,9 +612,9 @@ asCScriptEngine::asCScriptEngine()
|
||||
|
||||
void asCScriptEngine::DeleteDiscardedModules()
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Prevent more than one thread from entering this function at the same time.
|
||||
// If a thread is already doing the work for the clean-up the other thread should
|
||||
// simply return, as the first thread will continue.
|
||||
// TODO: redesign: Prevent more than one thread from entering this function at the same time.
|
||||
// If a thread is already doing the work for the clean-up the other thread should
|
||||
// simply return, as the first thread will continue.
|
||||
|
||||
ACQUIRESHARED(engineRWLock);
|
||||
asUINT maxCount = discardedModules.GetLength();
|
||||
@ -646,7 +650,7 @@ void asCScriptEngine::DeleteDiscardedModules()
|
||||
|
||||
asCScriptEngine::~asCScriptEngine()
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Clean up redundant code
|
||||
// TODO: clean-up: Clean up redundant code
|
||||
|
||||
asUINT n = 0;
|
||||
inDestructor = true;
|
||||
@ -690,12 +694,8 @@ asCScriptEngine::~asCScriptEngine()
|
||||
if( refCount.get() > 0 )
|
||||
WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ENGINE_REF_COUNT_ERROR_DURING_SHUTDOWN);
|
||||
|
||||
asSMapNode<int,asCDataType*> *cursor = 0;
|
||||
while( mapTypeIdToDataType.MoveFirst(&cursor) )
|
||||
{
|
||||
asDELETE(mapTypeIdToDataType.GetValue(cursor),asCDataType);
|
||||
mapTypeIdToDataType.Erase(cursor);
|
||||
}
|
||||
mapTypeIdToObjectType.EraseAll();
|
||||
mapTypeIdToFunction.EraseAll();
|
||||
|
||||
// First remove what is not used, so that other groups can be deleted safely
|
||||
defaultGroup.RemoveConfiguration(this, true);
|
||||
@ -1976,7 +1976,7 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as
|
||||
listPattern->Destroy(this);
|
||||
return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
|
||||
}
|
||||
func.name.Format("_beh_%d_", behaviour);
|
||||
func.name.Format("$beh%d", behaviour);
|
||||
|
||||
if( behaviour != asBEHAVE_FACTORY && behaviour != asBEHAVE_LIST_FACTORY )
|
||||
{
|
||||
@ -3229,7 +3229,7 @@ int asCScriptEngine::RegisterStringFactory(const char *datatype, const asSFuncPt
|
||||
return ConfigError(asOUT_OF_MEMORY, "RegisterStringFactory", datatype, 0);
|
||||
}
|
||||
|
||||
func->name = "_string_factory_";
|
||||
func->name = "$str";
|
||||
func->sysFuncIntf = newInterface;
|
||||
|
||||
asCBuilder bld(this, 0);
|
||||
@ -3591,6 +3591,9 @@ asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateT
|
||||
{
|
||||
asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, templateType->beh.listFactory);
|
||||
|
||||
// Rename the function to easily identify it in LoadByteCode
|
||||
func->name = "$list";
|
||||
|
||||
ot->beh.listFactory = func->id;
|
||||
}
|
||||
|
||||
@ -3787,7 +3790,7 @@ asCScriptFunction *asCScriptEngine::GenerateTemplateFactoryStub(asCObjectType *t
|
||||
|
||||
func->funcType = asFUNC_SCRIPT;
|
||||
func->AllocateScriptFunctionData();
|
||||
func->name = "factstub";
|
||||
func->name = "$fact";
|
||||
func->id = GetNextScriptFunctionId();
|
||||
AddScriptFunction(func);
|
||||
|
||||
@ -4230,6 +4233,62 @@ void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int func) const
|
||||
#endif
|
||||
}
|
||||
|
||||
void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const
|
||||
{
|
||||
asASSERT( func != 0 );
|
||||
asSSystemFunctionInterface *i = func->sysFuncIntf;
|
||||
|
||||
#ifndef AS_NO_CLASS_METHODS
|
||||
if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL )
|
||||
{
|
||||
#if defined(__GNUC__) || defined(AS_PSVITA)
|
||||
// For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable
|
||||
union
|
||||
{
|
||||
asSIMPLEMETHOD_t mthd;
|
||||
struct
|
||||
{
|
||||
asFUNCTION_t func;
|
||||
asPWORD baseOffset;
|
||||
} f;
|
||||
} p;
|
||||
p.f.func = (asFUNCTION_t)(i->func);
|
||||
p.f.baseOffset = asPWORD(i->baseOffset);
|
||||
void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))(p.mthd);
|
||||
return (((asCSimpleDummy*)obj)->*f)(param1);
|
||||
#else
|
||||
union
|
||||
{
|
||||
asSIMPLEMETHOD_t mthd;
|
||||
asFUNCTION_t func;
|
||||
} p;
|
||||
p.func = (asFUNCTION_t)(i->func);
|
||||
void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))p.mthd;
|
||||
obj = (void*)(asPWORD(obj) + i->baseOffset);
|
||||
return (((asCSimpleDummy*)obj)->*f)(param1);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if( i->callConv == ICC_GENERIC_METHOD )
|
||||
{
|
||||
asCGeneric gen(const_cast<asCScriptEngine*>(this), func, obj, reinterpret_cast<asDWORD*>(¶m1));
|
||||
void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
|
||||
f(&gen);
|
||||
return *(void **)gen.GetReturnPointer();
|
||||
}
|
||||
else if( i->callConv == ICC_CDECL_OBJLAST )
|
||||
{
|
||||
void *(*f)(int, void *) = (void *(*)(int, void *))(i->func);
|
||||
return f(param1, obj);
|
||||
}
|
||||
else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/
|
||||
{
|
||||
void *(*f)(void *, int) = (void *(*)(void *, int))(i->func);
|
||||
return f(obj, param1);
|
||||
}
|
||||
}
|
||||
|
||||
void *asCScriptEngine::CallGlobalFunctionRetPtr(int func) const
|
||||
{
|
||||
asCScriptFunction *s = scriptFunctions[func];
|
||||
@ -4496,82 +4555,154 @@ void asCScriptEngine::GCEnumCallback(void *reference)
|
||||
}
|
||||
|
||||
|
||||
// TODO: multithread: The mapTypeIdToDataType must be protected with critical sections in all functions that access it
|
||||
int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const
|
||||
{
|
||||
if( dtIn.IsNullHandle() ) return 0;
|
||||
if( dtIn.IsNullHandle() ) return asTYPEID_VOID;
|
||||
|
||||
// Register the base form
|
||||
asCDataType dt(dtIn);
|
||||
if( dt.GetObjectType() )
|
||||
dt.MakeHandle(false);
|
||||
|
||||
// Find the existing type id
|
||||
asSMapNode<int,asCDataType*> *cursor = 0;
|
||||
mapTypeIdToDataType.MoveFirst(&cursor);
|
||||
while( cursor )
|
||||
if( dtIn.GetObjectType() == 0 )
|
||||
{
|
||||
if( mapTypeIdToDataType.GetValue(cursor)->IsEqualExceptRefAndConst(dt) )
|
||||
// Primitives have pre-fixed typeIds
|
||||
switch( dtIn.GetTokenType() )
|
||||
{
|
||||
int typeId = mapTypeIdToDataType.GetKey(cursor);
|
||||
if( dtIn.GetObjectType() && !(dtIn.GetObjectType()->flags & asOBJ_ASHANDLE) )
|
||||
case ttVoid: return asTYPEID_VOID;
|
||||
case ttBool: return asTYPEID_BOOL;
|
||||
case ttInt8: return asTYPEID_INT8;
|
||||
case ttInt16: return asTYPEID_INT16;
|
||||
case ttInt: return asTYPEID_INT32;
|
||||
case ttInt64: return asTYPEID_INT64;
|
||||
case ttUInt8: return asTYPEID_UINT8;
|
||||
case ttUInt16: return asTYPEID_UINT16;
|
||||
case ttUInt: return asTYPEID_UINT32;
|
||||
case ttUInt64: return asTYPEID_UINT64;
|
||||
case ttFloat: return asTYPEID_FLOAT;
|
||||
case ttDouble: return asTYPEID_DOUBLE;
|
||||
default:
|
||||
// All types should be covered by the above. The variable type is not really a type
|
||||
asASSERT(dtIn.GetTokenType() == ttQuestion);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int typeId = -1;
|
||||
asCObjectType *ot = dtIn.GetObjectType();
|
||||
if( ot != &functionBehaviours )
|
||||
{
|
||||
// Object's hold the typeId themselves
|
||||
typeId = ot->typeId;
|
||||
|
||||
if( typeId == -1 )
|
||||
{
|
||||
ACQUIREEXCLUSIVE(engineRWLock);
|
||||
// Make sure another thread didn't determine the typeId while we were waiting for the lock
|
||||
if( ot->typeId == -1 )
|
||||
{
|
||||
// The ASHANDLE types behave like handles, but are really
|
||||
// value types so the typeId is never returned as a handle
|
||||
if( dtIn.IsObjectHandle() )
|
||||
typeId |= asTYPEID_OBJHANDLE;
|
||||
if( dtIn.IsHandleToConst() )
|
||||
typeId |= asTYPEID_HANDLETOCONST;
|
||||
typeId = typeIdSeqNbr++;
|
||||
if( ot->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT;
|
||||
else if( ot->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE;
|
||||
else if( ot->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this?
|
||||
else typeId |= asTYPEID_APPOBJECT;
|
||||
|
||||
ot->typeId = typeId;
|
||||
|
||||
mapTypeIdToObjectType.Insert(typeId, ot);
|
||||
}
|
||||
RELEASEEXCLUSIVE(engineRWLock);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This a funcdef, so we'll need to look in the map for the funcdef
|
||||
|
||||
// TODO: optimize: It shouldn't be necessary to exclusive lock when the typeId already exists
|
||||
ACQUIREEXCLUSIVE(engineRWLock);
|
||||
|
||||
// Find the existing type id
|
||||
asCScriptFunction *func = dtIn.GetFuncDef();
|
||||
asASSERT(func);
|
||||
asSMapNode<int,asCScriptFunction*> *cursor = 0;
|
||||
mapTypeIdToFunction.MoveFirst(&cursor);
|
||||
while( cursor )
|
||||
{
|
||||
if( mapTypeIdToFunction.GetValue(cursor) == func )
|
||||
{
|
||||
typeId = mapTypeIdToFunction.GetKey(cursor);
|
||||
break;
|
||||
}
|
||||
|
||||
return typeId;
|
||||
mapTypeIdToFunction.MoveNext(&cursor, cursor);
|
||||
}
|
||||
|
||||
mapTypeIdToDataType.MoveNext(&cursor, cursor);
|
||||
// The type id doesn't exist, create it
|
||||
if( typeId == -1 )
|
||||
{
|
||||
// Setup the type id for the funcdef
|
||||
typeId = typeIdSeqNbr++;
|
||||
typeId |= asTYPEID_APPOBJECT;
|
||||
mapTypeIdToFunction.Insert(typeId, func);
|
||||
}
|
||||
|
||||
RELEASEEXCLUSIVE(engineRWLock);
|
||||
}
|
||||
|
||||
// The type id doesn't exist, create it
|
||||
|
||||
// Setup the basic type id
|
||||
int typeId = typeIdSeqNbr++;
|
||||
if( dt.GetObjectType() )
|
||||
// Add flags according to the requested type
|
||||
if( dtIn.GetObjectType() && !(dtIn.GetObjectType()->flags & asOBJ_ASHANDLE) )
|
||||
{
|
||||
if( dt.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT;
|
||||
else if( dt.GetObjectType()->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE;
|
||||
else if( dt.GetObjectType()->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this?
|
||||
else typeId |= asTYPEID_APPOBJECT;
|
||||
// The ASHANDLE types behave like handles, but are really
|
||||
// value types so the typeId is never returned as a handle
|
||||
if( dtIn.IsObjectHandle() )
|
||||
typeId |= asTYPEID_OBJHANDLE;
|
||||
if( dtIn.IsHandleToConst() )
|
||||
typeId |= asTYPEID_HANDLETOCONST;
|
||||
}
|
||||
|
||||
// Insert the basic object type
|
||||
asCDataType *newDt = asNEW(asCDataType)(dt);
|
||||
if( newDt == 0 )
|
||||
{
|
||||
// Out of memory
|
||||
return 0;
|
||||
}
|
||||
|
||||
newDt->MakeReference(false);
|
||||
newDt->MakeReadOnly(false);
|
||||
newDt->MakeHandle(false);
|
||||
|
||||
mapTypeIdToDataType.Insert(typeId, newDt);
|
||||
|
||||
// Call recursively to get the correct typeId
|
||||
return GetTypeIdFromDataType(dtIn);
|
||||
return typeId;
|
||||
}
|
||||
|
||||
asCDataType asCScriptEngine::GetDataTypeFromTypeId(int typeId) const
|
||||
{
|
||||
int baseId = typeId & (asTYPEID_MASK_OBJECT | asTYPEID_MASK_SEQNBR);
|
||||
|
||||
asSMapNode<int,asCDataType*> *cursor = 0;
|
||||
if( mapTypeIdToDataType.MoveTo(&cursor, baseId) )
|
||||
if( typeId <= asTYPEID_DOUBLE )
|
||||
{
|
||||
asCDataType dt(*mapTypeIdToDataType.GetValue(cursor));
|
||||
eTokenType type[] = {ttVoid, ttBool, ttInt8, ttInt16, ttInt, ttInt64, ttUInt8, ttUInt16, ttUInt, ttUInt64, ttFloat, ttDouble};
|
||||
return asCDataType::CreatePrimitive(type[typeId], false);
|
||||
}
|
||||
|
||||
// First check if the typeId is an object type
|
||||
asCObjectType *ot = 0;
|
||||
ACQUIRESHARED(engineRWLock);
|
||||
asSMapNode<int,asCObjectType*> *cursor = 0;
|
||||
if( mapTypeIdToObjectType.MoveTo(&cursor, baseId) )
|
||||
ot = mapTypeIdToObjectType.GetValue(cursor);
|
||||
RELEASESHARED(engineRWLock);
|
||||
|
||||
if( ot )
|
||||
{
|
||||
asCDataType dt = asCDataType::CreateObject(ot, false);
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
dt.MakeHandle(true, true);
|
||||
if( typeId & asTYPEID_HANDLETOCONST )
|
||||
dt.MakeHandleToConst(true);
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
// Then check if it is a funcdef
|
||||
asCScriptFunction *func = 0;
|
||||
ACQUIRESHARED(engineRWLock);
|
||||
asSMapNode<int,asCScriptFunction*> *cursor2 = 0;
|
||||
if( mapTypeIdToFunction.MoveTo(&cursor2, baseId) )
|
||||
func = mapTypeIdToFunction.GetValue(cursor2);
|
||||
RELEASESHARED(engineRWLock);
|
||||
|
||||
if( func )
|
||||
{
|
||||
asCDataType dt = asCDataType::CreateFuncDef(func);
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
dt.MakeHandle(true, true);
|
||||
if( typeId & asTYPEID_HANDLETOCONST )
|
||||
dt.MakeHandleToConst(true);
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
@ -4586,19 +4717,19 @@ asCObjectType *asCScriptEngine::GetObjectTypeFromTypeId(int typeId) const
|
||||
|
||||
void asCScriptEngine::RemoveFromTypeIdMap(asCObjectType *type)
|
||||
{
|
||||
asSMapNode<int,asCDataType*> *cursor = 0;
|
||||
mapTypeIdToDataType.MoveFirst(&cursor);
|
||||
ACQUIREEXCLUSIVE(engineRWLock);
|
||||
asSMapNode<int,asCObjectType*> *cursor = 0;
|
||||
mapTypeIdToObjectType.MoveFirst(&cursor);
|
||||
while( cursor )
|
||||
{
|
||||
asCDataType *dt = mapTypeIdToDataType.GetValue(cursor);
|
||||
asSMapNode<int,asCDataType*> *old = cursor;
|
||||
mapTypeIdToDataType.MoveNext(&cursor, cursor);
|
||||
if( dt->GetObjectType() == type )
|
||||
if( mapTypeIdToObjectType.GetValue(cursor) == type )
|
||||
{
|
||||
asDELETE(dt,asCDataType);
|
||||
mapTypeIdToDataType.Erase(old);
|
||||
mapTypeIdToObjectType.Erase(cursor);
|
||||
break;
|
||||
}
|
||||
mapTypeIdToObjectType.MoveNext(&cursor, cursor);
|
||||
}
|
||||
RELEASEEXCLUSIVE(engineRWLock);
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -5318,7 +5449,6 @@ void asCScriptEngine::RemoveScriptFunction(asCScriptFunction *func)
|
||||
// internal
|
||||
void asCScriptEngine::RemoveFuncdef(asCScriptFunction *funcdef)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: How to avoid removing a funcdef that is shared by multiple modules?
|
||||
funcDefs.RemoveValue(funcdef);
|
||||
}
|
||||
|
||||
|
@ -238,6 +238,7 @@ public:
|
||||
bool CallObjectMethodRetBool(void *obj, int func) const;
|
||||
int CallObjectMethodRetInt(void *obj, int func) const;
|
||||
void *CallObjectMethodRetPtr(void *obj, int func) const;
|
||||
void *CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const;
|
||||
void CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const;
|
||||
bool CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const;
|
||||
|
||||
@ -400,16 +401,17 @@ public:
|
||||
// This array stores the template instances types that have been automatically generated from template types
|
||||
asCArray<asCObjectType *> generatedTemplateTypes;
|
||||
// Stores the funcdefs
|
||||
// TODO: 2.30.0: redesign: Only shared funcdefs should be stored here
|
||||
// a funcdef becomes shared if all arguments and the return type are shared (or application registered)
|
||||
// TODO: redesign: Only shared funcdefs should be stored here
|
||||
// a funcdef becomes shared if all arguments and the return type are shared (or application registered)
|
||||
asCArray<asCScriptFunction *> funcDefs; // doesn't increase ref count
|
||||
|
||||
// Stores the names of the script sections for debugging purposes
|
||||
asCArray<asCString *> scriptSectionNames;
|
||||
|
||||
// Type identifiers
|
||||
mutable int typeIdSeqNbr;
|
||||
mutable asCMap<int, asCDataType*> mapTypeIdToDataType;
|
||||
mutable int typeIdSeqNbr;
|
||||
mutable asCMap<int, asCObjectType*> mapTypeIdToObjectType;
|
||||
mutable asCMap<int, asCScriptFunction*> mapTypeIdToFunction;
|
||||
|
||||
// Garbage collector
|
||||
asCGarbageCollector gc;
|
||||
|
@ -105,7 +105,7 @@ static void ScriptFunction_CreateDelegate_Generic(asIScriptGeneric *gen)
|
||||
gen->SetReturnAddress(CreateDelegate(func, obj));
|
||||
}
|
||||
|
||||
// TODO: 2.29.0: operator==
|
||||
// TODO: operator==
|
||||
/*static void ScriptFunction_opEquals_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCScriptFunction *funcSelf = (asCScriptFunction*)gen->GetObject();
|
||||
@ -124,7 +124,7 @@ void RegisterScriptFunction(asCScriptEngine *engine)
|
||||
UNUSED_VAR(r); // It is only used in debug mode
|
||||
engine->functionBehaviours.engine = engine;
|
||||
engine->functionBehaviours.flags = asOBJ_REF | asOBJ_GC | asOBJ_SCRIPT_FUNCTION;
|
||||
engine->functionBehaviours.name = "_builtin_function_";
|
||||
engine->functionBehaviours.name = "$func";
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptFunction,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCScriptFunction,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
@ -133,7 +133,7 @@ void RegisterScriptFunction(asCScriptEngine *engine)
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptFunction,GetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptFunction,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptFunction,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
// TODO: 2.29.0: Need some way to allow the arg type to adapt when the funcdefs are instantiated
|
||||
// TODO: Need some way to allow the arg type to adapt when the funcdefs are instantiated
|
||||
// r = engine->RegisterMethodToObjectType(&engine->functionBehaviours, "bool opEquals(const int &in)", asMETHOD(asCScriptFunction,operator==), asCALL_THISCALL); asASSERT( r >= 0 );
|
||||
#else
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFunction_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
@ -226,7 +226,7 @@ asIScriptFunction *asCScriptFunction::GetDelegateFunction() const
|
||||
return funcForDelegate;
|
||||
}
|
||||
|
||||
// TODO: 2.29.0: operator==
|
||||
// TODO: operator==
|
||||
/*
|
||||
// internal
|
||||
bool asCScriptFunction::operator==(const asCScriptFunction &other) const
|
||||
@ -419,7 +419,6 @@ asCScriptFunction::~asCScriptFunction()
|
||||
// If the engine pointer is 0, then DestroyInternal has already been called and there is nothing more to do
|
||||
if( engine == 0 ) return;
|
||||
|
||||
// TODO: 2.30.0: redesign: Shouldn't this have been done already?
|
||||
DestroyInternal();
|
||||
|
||||
// Finally set the engine pointer to 0 because it must not be accessed again
|
||||
@ -678,7 +677,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
if( !(returnType.GetTokenType() == ttVoid &&
|
||||
objectType &&
|
||||
(name == objectType->name || (name.GetLength() > 0 && name[0] == '~') ||
|
||||
name == "_beh_0_" || name == "_beh_2_")) )
|
||||
name == "$beh0" || name == "$beh2")) )
|
||||
{
|
||||
str = returnType.Format(nameSpace, includeNamespace);
|
||||
str += " ";
|
||||
@ -699,13 +698,13 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
}
|
||||
if( name == "" )
|
||||
str += "_unnamed_function_(";
|
||||
else if( name.SubString(0,5) == "_beh_" && name.GetLength() == 7 )
|
||||
else if( name.SubString(0,4) == "$beh" && name.GetLength() == 5 )
|
||||
{
|
||||
if( name[5] == '0' + asBEHAVE_CONSTRUCT )
|
||||
if( name[4] == '0' + asBEHAVE_CONSTRUCT )
|
||||
str += objectType->name + "(";
|
||||
else if( name[5] == '0' + asBEHAVE_FACTORY )
|
||||
else if( name[4] == '0' + asBEHAVE_FACTORY )
|
||||
str += returnType.GetObjectType()->name + "(";
|
||||
else if( name[5] == '0' + asBEHAVE_DESTRUCT )
|
||||
else if( name[4] == '0' + asBEHAVE_DESTRUCT )
|
||||
str += "~" + objectType->name + "(";
|
||||
else
|
||||
str += name + "(";
|
||||
@ -1008,7 +1007,7 @@ void asCScriptFunction::ComputeSignatureId()
|
||||
// internal
|
||||
bool asCScriptFunction::IsSignatureEqual(const asCScriptFunction *func) const
|
||||
{
|
||||
if( !IsSignatureExceptNameEqual(func) || name != func->name ) return false;
|
||||
if( name != func->name || !IsSignatureExceptNameEqual(func) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1043,9 +1042,9 @@ bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCScriptF
|
||||
bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCArray<asCDataType> ¶mTypes, const asCArray<asETypeModifiers> ¶mInOut, const asCObjectType *objType, bool readOnly) const
|
||||
{
|
||||
if( this->isReadOnly != readOnly ) return false;
|
||||
if( (this->objectType != 0) != (objType != 0) ) return false;
|
||||
if( this->inOutFlags != paramInOut ) return false;
|
||||
if( this->parameterTypes != paramTypes ) return false;
|
||||
if( (this->objectType != 0) != (objType != 0) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1299,7 +1298,11 @@ void asCScriptFunction::ReleaseReferences()
|
||||
if( group != 0 ) group->Release();
|
||||
|
||||
if( funcId )
|
||||
engine->scriptFunctions[funcId]->ReleaseInternal();
|
||||
{
|
||||
asCScriptFunction *fptr = engine->scriptFunctions[funcId];
|
||||
if( fptr )
|
||||
fptr->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -186,12 +186,12 @@ public:
|
||||
|
||||
void DestroyHalfCreated();
|
||||
|
||||
// TODO: 2.29.0: operator==
|
||||
// TODO: 2.29.0: The asIScriptFunction should provide operator== and operator!= that should do a
|
||||
// a value comparison. Two delegate objects that point to the same object and class method should compare as equal
|
||||
// TODO: 2.29.0: The operator== should also be provided in script as opEquals to allow the same comparison in script
|
||||
// To do this we'll need some way to adapt the argtype for opEquals for each funcdef, preferrably without instantiating lots of different methods
|
||||
// Perhaps reusing 'auto' to mean the same type as the object
|
||||
// TODO: operator==
|
||||
// TODO: The asIScriptFunction should provide operator== and operator!= that should do a
|
||||
// a value comparison. Two delegate objects that point to the same object and class method should compare as equal
|
||||
// TODO: The operator== should also be provided in script as opEquals to allow the same comparison in script
|
||||
// To do this we'll need some way to adapt the argtype for opEquals for each funcdef, preferrably without instantiating lots of different methods
|
||||
// Perhaps reusing 'auto' to mean the same type as the object
|
||||
//bool operator==(const asCScriptFunction &other) const;
|
||||
|
||||
void DestroyInternal();
|
||||
@ -329,7 +329,7 @@ public:
|
||||
asSSystemFunctionInterface *sysFuncIntf;
|
||||
};
|
||||
|
||||
const char * const DELEGATE_FACTORY = "%delegate_factory";
|
||||
const char * const DELEGATE_FACTORY = "$dlgte";
|
||||
asCScriptFunction *CreateDelegate(asCScriptFunction *func, void *obj);
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -173,6 +173,24 @@ static void ScriptObject_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
|
||||
self->ReleaseAllHandles(engine);
|
||||
}
|
||||
|
||||
static void ScriptObject_Assignment_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCScriptObject *other = *(asCScriptObject**)gen->GetAddressOfArg(0);
|
||||
asCScriptObject *self = (asCScriptObject*)gen->GetObject();
|
||||
|
||||
*self = *other;
|
||||
|
||||
*(asCScriptObject**)gen->GetAddressOfReturnLocation() = self;
|
||||
}
|
||||
|
||||
static void ScriptObject_Construct_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *objType = *(asCObjectType**)gen->GetAddressOfArg(0);
|
||||
asCScriptObject *self = (asCScriptObject*)gen->GetObject();
|
||||
|
||||
ScriptObject_Construct(objType, self);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void RegisterScriptObject(asCScriptEngine *engine)
|
||||
@ -182,7 +200,7 @@ void RegisterScriptObject(asCScriptEngine *engine)
|
||||
UNUSED_VAR(r); // It is only used in debug mode
|
||||
engine->scriptTypeBehaviours.engine = engine;
|
||||
engine->scriptTypeBehaviours.flags = asOBJ_SCRIPT_OBJECT | asOBJ_REF | asOBJ_GC;
|
||||
engine->scriptTypeBehaviours.name = "_builtin_object_";
|
||||
engine->scriptTypeBehaviours.name = "$obj";
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptObject_Construct), asCALL_CDECL_OBJLAST, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptObject,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
@ -216,14 +234,6 @@ void RegisterScriptObject(asCScriptEngine *engine)
|
||||
#endif
|
||||
}
|
||||
|
||||
void ScriptObject_Construct_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *objType = *(asCObjectType**)gen->GetAddressOfArg(0);
|
||||
asCScriptObject *self = (asCScriptObject*)gen->GetObject();
|
||||
|
||||
ScriptObject_Construct(objType, self);
|
||||
}
|
||||
|
||||
void ScriptObject_Construct(asCObjectType *objType, asCScriptObject *self)
|
||||
{
|
||||
new(self) asCScriptObject(objType);
|
||||
@ -744,16 +754,6 @@ void asCScriptObject::ReleaseAllHandles(asIScriptEngine *engine)
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptObject_Assignment_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCScriptObject *other = *(asCScriptObject**)gen->GetAddressOfArg(0);
|
||||
asCScriptObject *self = (asCScriptObject*)gen->GetObject();
|
||||
|
||||
*self = *other;
|
||||
|
||||
*(asCScriptObject**)gen->GetAddressOfReturnLocation() = self;
|
||||
}
|
||||
|
||||
asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject *self)
|
||||
{
|
||||
return (*self = *other);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -154,9 +154,6 @@ asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject
|
||||
|
||||
void ScriptObject_ConstructUnitialized(asCObjectType *objType, asCScriptObject *self);
|
||||
|
||||
void ScriptObject_Construct_Generic(asIScriptGeneric *gen);
|
||||
void ScriptObject_Assignment_Generic(asIScriptGeneric *gen);
|
||||
|
||||
void RegisterScriptObject(asCScriptEngine *engine);
|
||||
|
||||
asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngine *engine);
|
||||
|
@ -142,6 +142,7 @@
|
||||
#define TXT_INVALID_CONTINUE "Invalid 'continue'"
|
||||
#define TXT_INVALID_ESCAPE_SEQUENCE "Invalid escape sequence"
|
||||
#define TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME "Invalid expression: ambiguous name"
|
||||
#define TXT_INVALID_EXPRESSION_LAMBDA "Invalid expression: stand-alone anonymous function"
|
||||
#define TXT_INVALID_OP_ON_METHOD "Invalid operation on method"
|
||||
#define TXT_INVALID_REF_PROP_ACCESS "Invalid reference. Property accessors cannot be used in combined read/write operations"
|
||||
#define TXT_INVALID_SCOPE "Invalid scope resolution"
|
||||
@ -252,6 +253,7 @@
|
||||
#define TXT_TOO_MANY_JUMP_LABELS "The function has too many jump labels to handle. Split the function into smaller ones."
|
||||
#define TXT_TOO_MANY_VALUES_FOR_LIST "Too many values to match pattern"
|
||||
#define TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE "Type '%s' is not available for this module"
|
||||
#define TXT_TYPE_s_NOT_TEMPLATE "Type '%s' is not a template type"
|
||||
|
||||
#define TXT_UNEXPECTED_END_OF_FILE "Unexpected end of file"
|
||||
#define TXT_UNEXPECTED_TOKEN_s "Unexpected token '%s'"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -311,6 +311,7 @@ const char * const OVERRIDE_TOKEN = "override";
|
||||
const char * const GET_TOKEN = "get";
|
||||
const char * const SET_TOKEN = "set";
|
||||
const char * const ABSTRACT_TOKEN = "abstract";
|
||||
const char * const FUNCTION_TOKEN = "function";
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -53,7 +53,6 @@ asCTypeInfo::asCTypeInfo()
|
||||
isExplicitHandle = false;
|
||||
qwordValue = 0;
|
||||
isLValue = false;
|
||||
isVoidExpression = false;
|
||||
isRefToLocal = false;
|
||||
}
|
||||
|
||||
@ -68,7 +67,6 @@ void asCTypeInfo::Set(const asCDataType &dt)
|
||||
isExplicitHandle = false;
|
||||
qwordValue = 0;
|
||||
isLValue = false;
|
||||
isVoidExpression = false;
|
||||
isRefToLocal = false;
|
||||
}
|
||||
|
||||
@ -135,6 +133,18 @@ void asCTypeInfo::SetUndefinedFuncHandle(asCScriptEngine *engine)
|
||||
isLValue = false;
|
||||
}
|
||||
|
||||
bool asCTypeInfo::IsUndefinedFuncHandle() const
|
||||
{
|
||||
if( isConstant == false ) return false;
|
||||
if( qwordValue == 0 ) return false;
|
||||
if( isLValue ) return false;
|
||||
if( dataType.GetObjectType() == 0 ) return false;
|
||||
if( dataType.GetObjectType()->name != "$func" ) return false;
|
||||
if( dataType.GetFuncDef() ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void asCTypeInfo::SetNullConstant()
|
||||
{
|
||||
Set(asCDataType::CreateNullHandle());
|
||||
@ -153,17 +163,19 @@ bool asCTypeInfo::IsNullConstant() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void asCTypeInfo::SetVoidExpression()
|
||||
void asCTypeInfo::SetVoid()
|
||||
{
|
||||
Set(asCDataType::CreatePrimitive(ttVoid, false));
|
||||
isLValue = false;
|
||||
isConstant = false;
|
||||
isVoidExpression = true;
|
||||
isConstant = true;
|
||||
}
|
||||
|
||||
bool asCTypeInfo::IsVoidExpression() const
|
||||
bool asCTypeInfo::IsVoid() const
|
||||
{
|
||||
return isVoidExpression;
|
||||
if( dataType.GetTokenType() == ttVoid )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void asCTypeInfo::SetDummy()
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -61,11 +61,12 @@ struct asCTypeInfo
|
||||
void SetConstantD(const asCDataType &dataType, double value);
|
||||
void SetNullConstant();
|
||||
void SetUndefinedFuncHandle(asCScriptEngine *engine);
|
||||
void SetVoidExpression();
|
||||
void SetVoid();
|
||||
void SetDummy();
|
||||
|
||||
bool IsUndefinedFuncHandle() const;
|
||||
bool IsNullConstant() const;
|
||||
bool IsVoidExpression() const;
|
||||
bool IsVoid() const;
|
||||
|
||||
asCDataType dataType;
|
||||
bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc
|
||||
@ -73,9 +74,8 @@ struct asCTypeInfo
|
||||
bool isConstant : 1;
|
||||
bool isVariable : 1;
|
||||
bool isExplicitHandle : 1;
|
||||
bool isVoidExpression : 1;
|
||||
bool isRefToLocal : 1; // The reference may be to a local variable
|
||||
short dummy : 9;
|
||||
short dummy : 10;
|
||||
short stackOffset;
|
||||
union
|
||||
{
|
||||
|
@ -593,9 +593,9 @@ namespace UserConfigParams
|
||||
"stun.voxgratia.org",
|
||||
"stun.xten.com") );
|
||||
|
||||
PARAM_PREFIX StringUserConfigParam m_packets_log_filename
|
||||
PARAM_DEFAULT( StringUserConfigParam("packets_log.txt", "packets_log_filename",
|
||||
"Where to log received and sent packets.") );
|
||||
PARAM_PREFIX BoolUserConfigParam m_log_packets
|
||||
PARAM_DEFAULT( BoolUserConfigParam(false, "log-network-packets",
|
||||
"If all network packets should be logged") );
|
||||
|
||||
// ---- Graphic Quality
|
||||
PARAM_PREFIX GroupUserConfigParam m_graphics_quality
|
||||
|
@ -36,7 +36,7 @@ private:
|
||||
public:
|
||||
HitSFX(const Vec3& coord, const char* explosion_sound);
|
||||
~HitSFX();
|
||||
virtual bool updateAndDelete(float dt);
|
||||
virtual bool updateAndDelete(float dt) OVERRIDE;
|
||||
virtual void setLocalPlayerKartHit() OVERRIDE;
|
||||
|
||||
}; // HitSFX
|
||||
|
@ -18,7 +18,6 @@
|
||||
#ifndef HEADER_SHADERS_HPP
|
||||
#define HEADER_SHADERS_HPP
|
||||
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/shader.hpp"
|
||||
#include "graphics/shared_gpu_objects.hpp"
|
||||
#include "graphics/texture_shader.hpp"
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "graphics/shadow_matrices.hpp"
|
||||
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/glwrap.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
|
@ -84,7 +84,7 @@ public:
|
||||
virtual void collectChar(irr::video::ITexture* texture,
|
||||
const irr::core::rect<irr::s32>& destRect,
|
||||
const irr::core::rect<irr::s32>& sourceRect,
|
||||
const irr::video::SColor* const colors);
|
||||
const irr::video::SColor* const colors) OVERRIDE;
|
||||
|
||||
virtual void updateAbsolutePosition() OVERRIDE;
|
||||
};
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
m_render_type = "achievement-message::neutral";
|
||||
else if (mt==MessageQueue::MT_ERROR)
|
||||
m_render_type = "error-message::neutral";
|
||||
else if (mt==MessageQueue::MT_GENERIC)
|
||||
m_render_type = "generic-message::neutral";
|
||||
else
|
||||
m_render_type = "friend-message::neutral";
|
||||
} // Message
|
||||
|
@ -34,7 +34,7 @@ namespace MessageQueue
|
||||
* different look. This type is used to sort the messages, so it is
|
||||
* important that messages that need to be shown as early as possible
|
||||
* will be listed last (i.e. have highest priority). */
|
||||
enum MessageType { MT_FRIEND, MT_ACHIEVEMENT, MT_ERROR};
|
||||
enum MessageType { MT_FRIEND, MT_ACHIEVEMENT, MT_ERROR, MT_GENERIC};
|
||||
|
||||
void add(MessageType mt, const core::stringw &message);
|
||||
void updatePosition();
|
||||
|
@ -126,14 +126,14 @@ void GamepadConfig::setDefaultBinds ()
|
||||
{
|
||||
setBinding(PA_STEER_LEFT, Input::IT_STICKMOTION, 0, Input::AD_NEGATIVE);
|
||||
setBinding(PA_STEER_RIGHT, Input::IT_STICKMOTION, 0, Input::AD_POSITIVE);
|
||||
setBinding(PA_ACCEL, Input::IT_STICKMOTION, 1, Input::AD_NEGATIVE);
|
||||
setBinding(PA_BRAKE, Input::IT_STICKMOTION, 1, Input::AD_POSITIVE);
|
||||
setBinding(PA_FIRE, Input::IT_STICKBUTTON, 0);
|
||||
setBinding(PA_NITRO, Input::IT_STICKBUTTON, 1);
|
||||
setBinding(PA_DRIFT, Input::IT_STICKBUTTON, 2);
|
||||
setBinding(PA_RESCUE, Input::IT_STICKBUTTON, 3);
|
||||
setBinding(PA_LOOK_BACK, Input::IT_STICKBUTTON, 4);
|
||||
setBinding(PA_PAUSE_RACE, Input::IT_STICKBUTTON, 5);
|
||||
setBinding(PA_ACCEL, Input::IT_STICKBUTTON, 0, Input::AD_NEGATIVE);
|
||||
setBinding(PA_BRAKE, Input::IT_STICKBUTTON, 3, Input::AD_POSITIVE);
|
||||
setBinding(PA_FIRE, Input::IT_STICKBUTTON, 1);
|
||||
setBinding(PA_NITRO, Input::IT_STICKBUTTON, 4);
|
||||
setBinding(PA_DRIFT, Input::IT_STICKBUTTON, 5);
|
||||
setBinding(PA_RESCUE, Input::IT_STICKBUTTON, 8);
|
||||
setBinding(PA_LOOK_BACK, Input::IT_STICKBUTTON, 6);
|
||||
setBinding(PA_PAUSE_RACE, Input::IT_STICKBUTTON, 9);
|
||||
|
||||
setBinding(PA_MENU_UP, Input::IT_STICKMOTION, 1, Input::AD_NEGATIVE);
|
||||
setBinding(PA_MENU_DOWN, Input::IT_STICKMOTION, 1, Input::AD_POSITIVE);
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
|
||||
core::stringw toString();
|
||||
|
||||
virtual void save(std::ofstream& stream);
|
||||
virtual void save(std::ofstream& stream) OVERRIDE;
|
||||
void setDefaultBinds ();
|
||||
virtual core::stringw getBindingAsString(const PlayerAction action) const OVERRIDE;
|
||||
virtual bool load(const XMLNode *config) OVERRIDE;
|
||||
@ -81,7 +81,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if this device should desensitize its input at values
|
||||
* close to 0 (to avoid 'oversteering'). */
|
||||
virtual bool desensitize() const { return m_desensitize;}
|
||||
virtual bool desensitize() const OVERRIDE { return m_desensitize;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of buttons in this configuration. */
|
||||
@ -103,9 +103,9 @@ public:
|
||||
/** Return deadzone of this configuration. */
|
||||
int getDeadzone() const { return m_deadzone; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isGamePad() const { return true; }
|
||||
virtual bool isGamePad() const OVERRIDE { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isKeyboard() const { return false; }
|
||||
virtual bool isKeyboard() const OVERRIDE { return false; }
|
||||
|
||||
}; // class GamepadConfig
|
||||
|
||||
|
@ -367,8 +367,8 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
case KEY_F10:
|
||||
if(world && value)
|
||||
{
|
||||
if(control_is_pressed && ReplayRecorder::get())
|
||||
ReplayRecorder::get()->Save();
|
||||
if(control_is_pressed)
|
||||
ReplayRecorder::get()->save();
|
||||
else
|
||||
history->Save();
|
||||
}
|
||||
|
@ -213,6 +213,7 @@ FileManager::FileManager()
|
||||
checkAndCreateConfigDir();
|
||||
checkAndCreateAddonsDir();
|
||||
checkAndCreateScreenshotDir();
|
||||
checkAndCreateReplayDir();
|
||||
checkAndCreateCachedTexturesDir();
|
||||
checkAndCreateGPDir();
|
||||
|
||||
@ -641,6 +642,14 @@ std::string FileManager::getScreenshotDir() const
|
||||
return m_screenshot_dir;
|
||||
} // getScreenshotDir
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the directory in which replay file should be stored.
|
||||
*/
|
||||
std::string FileManager::getReplayDir() const
|
||||
{
|
||||
return m_replay_dir;
|
||||
} // getReplayDir
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the directory in which resized textures should be cached.
|
||||
*/
|
||||
@ -910,6 +919,32 @@ void FileManager::checkAndCreateScreenshotDir()
|
||||
|
||||
} // checkAndCreateScreenshotDir
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Creates the directories for replay recorded. This will set m_replay_dir
|
||||
* with the appropriate path.
|
||||
*/
|
||||
void FileManager::checkAndCreateReplayDir()
|
||||
{
|
||||
#if defined(WIN32) || defined(__CYGWIN__)
|
||||
m_replay_dir = m_user_config_dir + "replay/";
|
||||
#elif defined(__APPLE__)
|
||||
m_replay_dir = getenv("HOME");
|
||||
m_replay_dir += "/Library/Application Support/SuperTuxKart/replay/";
|
||||
#else
|
||||
m_replay_dir = checkAndCreateLinuxDir("XDG_DATA_HOME", "supertuxkart",
|
||||
".local/share", ".supertuxkart");
|
||||
m_replay_dir += "replay/";
|
||||
#endif
|
||||
|
||||
if(!checkAndCreateDirectory(m_replay_dir))
|
||||
{
|
||||
Log::error("FileManager", "Can not create replay directory '%s', "
|
||||
"falling back to '.'.", m_replay_dir.c_str());
|
||||
m_replay_dir = ".";
|
||||
}
|
||||
|
||||
} // checkAndCreateReplayDir
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Creates the directories for cached textures. This will set
|
||||
* m_cached_textures_dir with the appropriate path.
|
||||
|
@ -75,6 +75,9 @@ private:
|
||||
/** Directory to store screenshots in. */
|
||||
std::string m_screenshot_dir;
|
||||
|
||||
/** Directory to store replays in. */
|
||||
std::string m_replay_dir;
|
||||
|
||||
/** Directory where resized textures are cached. */
|
||||
std::string m_cached_textures_dir;
|
||||
|
||||
@ -97,6 +100,7 @@ private:
|
||||
bool isDirectory(const std::string &path) const;
|
||||
void checkAndCreateAddonsDir();
|
||||
void checkAndCreateScreenshotDir();
|
||||
void checkAndCreateReplayDir();
|
||||
void checkAndCreateCachedTexturesDir();
|
||||
void checkAndCreateGPDir();
|
||||
void discoverPaths();
|
||||
@ -118,6 +122,7 @@ public:
|
||||
XMLNode *createXMLTreeFromString(const std::string & content);
|
||||
|
||||
std::string getScreenshotDir() const;
|
||||
std::string getReplayDir() const;
|
||||
std::string getCachedTexturesDir() const;
|
||||
std::string getGPDir() const;
|
||||
std::string getTextureCacheLocation(const std::string& filename);
|
||||
@ -146,6 +151,9 @@ public:
|
||||
return fileExists(std::string(prefix) + path);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of the stdout file for log messages. */
|
||||
static const std::string& getStdoutName() { return m_stdout_filename; }
|
||||
// ------------------------------------------------------------------------
|
||||
void listFiles (std::set<std::string>& result,
|
||||
const std::string& dir,
|
||||
bool make_full_path=false) const;
|
||||
|
@ -480,6 +480,7 @@ void Flyable::explode(AbstractKart *kart_hit, PhysicalObject *object,
|
||||
->getKartTeam(m_owner->getWorldKartId()))
|
||||
continue;
|
||||
}
|
||||
if (kart->isGhostKart()) continue;
|
||||
|
||||
// If no secondary hits should be done, only hit the
|
||||
// direct hit kart.
|
||||
|
@ -294,7 +294,7 @@ void Powerup::use()
|
||||
for(unsigned int i = 0 ; i < world->getNumKarts(); ++i)
|
||||
{
|
||||
AbstractKart *kart=world->getKart(i);
|
||||
if(kart->isEliminated()) continue;
|
||||
if(kart->isEliminated() || kart->isInvulnerable()) continue;
|
||||
if(kart == m_owner) continue;
|
||||
if(kart->getPosition() == 1)
|
||||
{
|
||||
@ -328,7 +328,7 @@ void Powerup::use()
|
||||
for(unsigned int i = 0 ; i < world->getNumKarts(); ++i)
|
||||
{
|
||||
AbstractKart *kart=world->getKart(i);
|
||||
if(kart->isEliminated() || kart== m_owner) continue;
|
||||
if(kart->isEliminated() || kart== m_owner || kart->isInvulnerable()) continue;
|
||||
if(kart->isShielded())
|
||||
{
|
||||
kart->decreaseShieldTime();
|
||||
|
@ -40,7 +40,14 @@ AbstractKart::AbstractKart(const std::string& ident,
|
||||
{
|
||||
m_world_kart_id = world_kart_id;
|
||||
m_kart_properties.reset(new KartProperties());
|
||||
m_kart_properties->copyForPlayer(kart_properties_manager->getKart(ident));
|
||||
const KartProperties* kp = kart_properties_manager->getKart(ident);
|
||||
if (kp == NULL)
|
||||
{
|
||||
Log::warn("Abstract_Kart", "Unknown kart %s, fallback to tux",
|
||||
ident.c_str());
|
||||
kp = kart_properties_manager->getKart(std::string("tux"));
|
||||
}
|
||||
m_kart_properties->copyForPlayer(kp);
|
||||
m_difficulty = difficulty;
|
||||
m_kart_animation = NULL;
|
||||
assert(m_kart_properties);
|
||||
|
@ -46,6 +46,7 @@ class Material;
|
||||
class Powerup;
|
||||
class Skidding;
|
||||
class SlipStream;
|
||||
class TerrainInfo;
|
||||
|
||||
/** An abstract interface for the actual karts. Some functions are actually
|
||||
* implemented here in order to allow inlining.
|
||||
@ -421,6 +422,9 @@ public:
|
||||
/** Shows the star effect for a certain time. */
|
||||
virtual void showStarEffect(float t) = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the terrain info oject. */
|
||||
virtual const TerrainInfo *getTerrainInfo() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when the kart crashes against another kart.
|
||||
* \param k The kart that was hit.
|
||||
* \param update_attachments If true the attachment of this kart and the
|
||||
@ -450,6 +454,12 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart wins or loses. */
|
||||
virtual bool getRaceResult() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart is a ghost (replay) kart. */
|
||||
virtual bool isGhostKart() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart is jumping. */
|
||||
virtual bool isJumping() const = 0;
|
||||
|
||||
}; // AbstractKart
|
||||
|
||||
|
@ -63,7 +63,7 @@ protected:
|
||||
void setControllerName(const std::string &name);
|
||||
float steerToPoint(const Vec3 &point);
|
||||
float normalizeAngle(float angle);
|
||||
virtual void update (float delta) ;
|
||||
virtual void update (float delta);
|
||||
virtual void setSteering (float angle, float dt);
|
||||
virtual bool canSkid(float steer_fraction) = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
|
60
src/karts/controller/ghost_controller.cpp
Normal file
60
src/karts/controller/ghost_controller.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "karts/controller/ghost_controller.hpp"
|
||||
#include "modes/world.hpp"
|
||||
|
||||
GhostController::GhostController(AbstractKart *kart)
|
||||
: Controller(kart)
|
||||
{
|
||||
} // GhostController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void GhostController::reset()
|
||||
{
|
||||
m_current_index = 0;
|
||||
m_current_time = 0.0f;
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void GhostController::update(float dt)
|
||||
{
|
||||
m_current_time = World::getWorld()->getTime();
|
||||
// Find (if necessary) the next index to use
|
||||
if (m_current_time != 0.0f)
|
||||
{
|
||||
while (m_current_index + 1 < m_all_times.size() &&
|
||||
m_current_time >= m_all_times[m_current_index + 1])
|
||||
{
|
||||
m_current_index++;
|
||||
}
|
||||
}
|
||||
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void GhostController::addReplayTime(float time)
|
||||
{
|
||||
// FIXME: for now avoid that transforms for the same time are set
|
||||
// twice (to avoid division by zero in update). This should be
|
||||
// done when saving in replay
|
||||
if (m_all_times.size() > 0 && m_all_times.back() == time)
|
||||
return;
|
||||
m_all_times.push_back(time);
|
||||
|
||||
} // addReplayTime
|
78
src/karts/controller/ghost_controller.hpp
Normal file
78
src/karts/controller/ghost_controller.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_GHOST_CONTROLLER_HPP
|
||||
#define HEADER_GHOST_CONTROLLER_HPP
|
||||
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/** A class for Ghost controller.
|
||||
* \ingroup controller
|
||||
*/
|
||||
class GhostController : public Controller
|
||||
{
|
||||
private:
|
||||
/** Pointer to the last index in m_all_times that is smaller than
|
||||
* the current world time. */
|
||||
unsigned int m_current_index;
|
||||
|
||||
/** The current world time. */
|
||||
float m_current_time;
|
||||
|
||||
/** The list of the times at which the events of kart were reached. */
|
||||
std::vector<float> m_all_times;
|
||||
|
||||
public:
|
||||
GhostController(AbstractKart *kart);
|
||||
virtual ~GhostController() {};
|
||||
virtual void reset();
|
||||
virtual void update (float dt);
|
||||
virtual bool disableSlipstreamBonus() const { return true; }
|
||||
virtual void crashed(const Material *m) {};
|
||||
virtual void crashed(const AbstractKart *k) {};
|
||||
virtual void handleZipper(bool play_sound) {};
|
||||
virtual void finishedRace(float time) {};
|
||||
virtual void collectedItem(const Item &item, int add_info=-1,
|
||||
float previous_energy=0) {};
|
||||
virtual void setPosition(int p) {};
|
||||
virtual bool isPlayerController() const { return false; }
|
||||
virtual bool isLocalPlayerController() const { return false; }
|
||||
virtual void action(PlayerAction action, int value) {};
|
||||
virtual void skidBonusTriggered() {};
|
||||
virtual void newLap(int lap) {};
|
||||
void addReplayTime(float time);
|
||||
// ------------------------------------------------------------------------
|
||||
bool isReplayEnd() const
|
||||
{ return m_current_index + 1 >= m_all_times.size(); }
|
||||
// ------------------------------------------------------------------------
|
||||
float getReplayDelta() const
|
||||
{
|
||||
assert(m_current_index < m_all_times.size());
|
||||
return ((m_current_time - m_all_times[m_current_index]) /
|
||||
(m_all_times[m_current_index + 1] - m_all_times[m_current_index]));
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
unsigned int getCurrentReplayIndex() const
|
||||
{ return m_current_index; }
|
||||
// ------------------------------------------------------------------------
|
||||
}; // GhostController
|
||||
|
||||
#endif
|
@ -75,7 +75,7 @@ public:
|
||||
virtual bool isLocalPlayerController() const OVERRIDE {return true;}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of the player profile. */
|
||||
core::stringw getName() const { return m_player->getProfile()->getName(); }
|
||||
core::stringw getName() const OVERRIDE { return m_player->getProfile()->getName(); }
|
||||
|
||||
|
||||
}; // LocalPlayerController
|
||||
|
@ -64,22 +64,22 @@ public:
|
||||
{
|
||||
} // setPosition
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void crashed(const AbstractKart *k)
|
||||
virtual void crashed(const AbstractKart *k) OVERRIDE
|
||||
{
|
||||
} // crashed(AbstractKart)
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void crashed(const Material *m)
|
||||
virtual void crashed(const Material *m) OVERRIDE
|
||||
{
|
||||
} // crashed(Material)
|
||||
// ------------------------------------------------------------------------
|
||||
/** Callback whenever a new lap is triggered. Used by the AI
|
||||
* to trigger a recomputation of the way to use, not used for players. */
|
||||
virtual void newLap(int lap)
|
||||
virtual void newLap(int lap) OVERRIDE
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Player will always be able to get a slipstream bonus. */
|
||||
virtual bool disableSlipstreamBonus() const
|
||||
virtual bool disableSlipstreamBonus() const OVERRIDE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -333,7 +333,8 @@ void SkiddingAI::update(float dt)
|
||||
|
||||
// If we are faster, try to predict the point where we will hit
|
||||
// the other kart
|
||||
if(m_kart_ahead->getSpeed() < m_kart->getSpeed())
|
||||
if((m_kart_ahead->getSpeed() < m_kart->getSpeed()) &&
|
||||
!m_kart_ahead->isGhostKart())
|
||||
{
|
||||
float time_till_hit = m_distance_ahead
|
||||
/ (m_kart->getSpeed()-m_kart_ahead->getSpeed());
|
||||
@ -1757,7 +1758,7 @@ void SkiddingAI::checkCrashes(const Vec3& pos )
|
||||
{
|
||||
const AbstractKart* kart = m_world->getKart(j);
|
||||
// Ignore eliminated karts
|
||||
if(kart==m_kart||kart->isEliminated()) continue;
|
||||
if(kart==m_kart||kart->isEliminated()||kart->isGhostKart()) continue;
|
||||
const AbstractKart *other_kart = m_world->getKart(j);
|
||||
// Ignore karts ahead that are faster than this kart.
|
||||
if(m_kart->getVelocityLC().getZ() < other_kart->getVelocityLC().getZ())
|
||||
|
@ -17,17 +17,19 @@
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "karts/ghost_kart.hpp"
|
||||
#include "karts/controller/ghost_controller.hpp"
|
||||
#include "karts/kart_gfx.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
#include "modes/world.hpp"
|
||||
|
||||
#include "LinearMath/btQuaternion.h"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
GhostKart::GhostKart(const std::string& ident)
|
||||
: Kart(ident, /*world kart id*/99999,
|
||||
/*position*/-1, btTransform(), PLAYER_DIFFICULTY_NORMAL)
|
||||
GhostKart::GhostKart(const std::string& ident, unsigned int world_kart_id,
|
||||
int position)
|
||||
: Kart(ident, world_kart_id,
|
||||
position, btTransform(btQuaternion(0, 0, 0, 1)),
|
||||
PLAYER_DIFFICULTY_NORMAL)
|
||||
{
|
||||
m_current_transform = 0;
|
||||
m_next_event = 0;
|
||||
} // GhostKart
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -35,84 +37,108 @@ void GhostKart::reset()
|
||||
{
|
||||
m_node->setVisible(true);
|
||||
Kart::reset();
|
||||
m_current_transform = 0;
|
||||
m_next_event = 0;
|
||||
// This will set the correct start position
|
||||
update(0);
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets the next time and transform. The current time and transform becomes
|
||||
* the previous time and transform.
|
||||
* \param
|
||||
*/
|
||||
void GhostKart::addTransform(float time, const btTransform &trans)
|
||||
void GhostKart::addReplayEvent(float time,
|
||||
const btTransform &trans,
|
||||
const ReplayBase::PhysicInfo &pi,
|
||||
const ReplayBase::KartReplayEvent &kre)
|
||||
{
|
||||
// FIXME: for now avoid that transforms for the same time are set
|
||||
// twice (to avoid division by zero in update). This should be
|
||||
// done when saving in replay
|
||||
if(m_all_times.size()>0 && m_all_times.back()==time)
|
||||
return;
|
||||
m_all_times.push_back(time);
|
||||
m_all_transform.push_back(trans);
|
||||
} // addTransform
|
||||
GhostController* gc = dynamic_cast<GhostController*>(getController());
|
||||
gc->addReplayTime(time);
|
||||
|
||||
m_all_transform.push_back(trans);
|
||||
m_all_physic_info.push_back(pi);
|
||||
m_all_replay_events.push_back(kre);
|
||||
|
||||
// Use first frame of replay to calculate default suspension
|
||||
if (m_all_physic_info.size() == 1)
|
||||
{
|
||||
float f = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
f += m_all_physic_info[0].m_suspension_length[i];
|
||||
m_graphical_y_offset = -f / 4 + getKartModel()->getLowestPoint();
|
||||
m_kart_model->setDefaultSuspension();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Adds a replay event for this kart.
|
||||
*/
|
||||
void GhostKart::addReplayEvent(const ReplayBase::KartReplayEvent &kre)
|
||||
{
|
||||
m_replay_events.push_back(kre);
|
||||
} // addReplayEvent
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Updates the ghost data each time step. It uses interpolation to get a new
|
||||
* position and rotation.
|
||||
/** Updates the current event of the ghost kart using interpolation
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void GhostKart::update(float dt)
|
||||
{
|
||||
float t = World::getWorld()->getTime();
|
||||
// Don't do anything at startup
|
||||
if(t==0) return;
|
||||
updateTransform(t, dt);
|
||||
while(m_next_event < m_replay_events.size() &&
|
||||
m_replay_events[m_next_event].m_time <= t)
|
||||
{
|
||||
Log::debug("Ghost_Kart", "Handling event %d", m_next_event);
|
||||
// Handle the next event now
|
||||
m_next_event++;
|
||||
}
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Updates the current transform of the ghost kart using interpolation
|
||||
* \param t Current world time.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void GhostKart::updateTransform(float t, float dt)
|
||||
{
|
||||
GhostController* gc = dynamic_cast<GhostController*>(getController());
|
||||
if (gc == NULL) return;
|
||||
|
||||
// Find (if necessary) the next index to use
|
||||
while(m_current_transform+1 < m_all_times.size() &&
|
||||
t>=m_all_times[m_current_transform+1])
|
||||
{
|
||||
m_current_transform ++;
|
||||
}
|
||||
if(m_current_transform+1>=m_all_times.size())
|
||||
gc->update(dt);
|
||||
if (gc->isReplayEnd())
|
||||
{
|
||||
m_node->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
float f =(t - m_all_times[m_current_transform])
|
||||
/ ( m_all_times[m_current_transform+1]
|
||||
- m_all_times[m_current_transform] );
|
||||
setXYZ((1-f)*m_all_transform[m_current_transform ].getOrigin()
|
||||
+ f *m_all_transform[m_current_transform+1].getOrigin() );
|
||||
const btQuaternion q = m_all_transform[m_current_transform].getRotation()
|
||||
.slerp(m_all_transform[m_current_transform+1]
|
||||
.getRotation(),
|
||||
f);
|
||||
const unsigned int idx = gc->getCurrentReplayIndex();
|
||||
const float rd = gc->getReplayDelta();
|
||||
assert(idx < m_all_transform.size());
|
||||
|
||||
float nitro_frac = 0;
|
||||
if (m_all_replay_events[idx].m_on_nitro)
|
||||
{
|
||||
nitro_frac = fabsf(m_all_physic_info[idx].m_speed) /
|
||||
(m_kart_properties->getEngineMaxSpeed());
|
||||
|
||||
if (nitro_frac > 1.0f)
|
||||
nitro_frac = 1.0f;
|
||||
}
|
||||
getKartGFX()->updateNitroGraphics(nitro_frac);
|
||||
|
||||
if (m_all_replay_events[idx].m_on_zipper)
|
||||
showZipperFire();
|
||||
|
||||
setXYZ((1- rd)*m_all_transform[idx ].getOrigin()
|
||||
+ rd *m_all_transform[idx + 1].getOrigin() );
|
||||
|
||||
const btQuaternion q = m_all_transform[idx].getRotation()
|
||||
.slerp(m_all_transform[idx + 1].getRotation(), rd);
|
||||
setRotation(q);
|
||||
Moveable::updateGraphics(dt, Vec3(0,0,0), btQuaternion(0, 0, 0, 1));
|
||||
|
||||
Vec3 center_shift(0, 0, 0);
|
||||
center_shift.setY(m_graphical_y_offset);
|
||||
center_shift = getTrans().getBasis() * center_shift;
|
||||
|
||||
Moveable::updateGraphics(dt, center_shift, btQuaternion(0, 0, 0, 1));
|
||||
getKartModel()->update(dt, dt*(m_all_physic_info[idx].m_speed),
|
||||
m_all_physic_info[idx].m_steer, m_all_physic_info[idx].m_speed, idx);
|
||||
getKartGFX()->update(dt);
|
||||
|
||||
Vec3 front(0, 0, getKartLength()*0.5f);
|
||||
m_xyz_front = getTrans()(front);
|
||||
|
||||
if (m_all_replay_events[idx].m_jumping && !m_is_jumping)
|
||||
{
|
||||
m_is_jumping = true;
|
||||
getKartModel()->setAnimation(KartModel::AF_JUMP_START);
|
||||
}
|
||||
else if (!m_all_replay_events[idx].m_jumping && m_is_jumping)
|
||||
{
|
||||
m_is_jumping = false;
|
||||
getKartModel()->setAnimation(KartModel::AF_DEFAULT);
|
||||
}
|
||||
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns the speed of the kart in meters/second. */
|
||||
float GhostKart::getSpeed() const
|
||||
{
|
||||
const GhostController* gc =
|
||||
dynamic_cast<const GhostController*>(getController());
|
||||
|
||||
assert(gc->getCurrentReplayIndex() < m_all_physic_info.size());
|
||||
return m_all_physic_info[gc->getCurrentReplayIndex()].m_speed;
|
||||
} // getSpeed
|
||||
|
@ -36,37 +36,46 @@
|
||||
class GhostKart : public Kart
|
||||
{
|
||||
private:
|
||||
/** The list of the times at which the transform were reached. */
|
||||
std::vector<float> m_all_times;
|
||||
|
||||
/** The transforms to assume at the corresponding time in m_all_times. */
|
||||
std::vector<btTransform> m_all_transform;
|
||||
std::vector<btTransform> m_all_transform;
|
||||
|
||||
std::vector<ReplayBase::KartReplayEvent> m_replay_events;
|
||||
std::vector<ReplayBase::PhysicInfo> m_all_physic_info;
|
||||
|
||||
/** Pointer to the last index in m_all_times that is smaller than
|
||||
* the current world time. */
|
||||
unsigned int m_current_transform;
|
||||
std::vector<ReplayBase::KartReplayEvent> m_all_replay_events;
|
||||
|
||||
/** Index of the next kart replay event. */
|
||||
unsigned int m_next_event;
|
||||
|
||||
void updateTransform(float t, float dt);
|
||||
public:
|
||||
GhostKart(const std::string& ident);
|
||||
virtual void update (float dt);
|
||||
virtual void addTransform(float time, const btTransform &trans);
|
||||
virtual void addReplayEvent(const ReplayBase::KartReplayEvent &kre);
|
||||
virtual void reset();
|
||||
GhostKart(const std::string& ident,
|
||||
unsigned int world_kart_id, int position);
|
||||
virtual void update (float dt);
|
||||
virtual void reset();
|
||||
// ------------------------------------------------------------------------
|
||||
/** No physics body for ghost kart, so nothing to adjust. */
|
||||
virtual void updateWeight() {};
|
||||
virtual void updateWeight() {};
|
||||
// ------------------------------------------------------------------------
|
||||
/** No physics for ghost kart. */
|
||||
virtual void applyEngineForce (float force) {}
|
||||
virtual void applyEngineForce (float force) {};
|
||||
// ------------------------------------------------------------------------
|
||||
// Not needed to create any physics for a ghost kart.
|
||||
virtual void createPhysics() {}
|
||||
virtual void createPhysics() {};
|
||||
// ------------------------------------------------------------------------
|
||||
const float getSuspensionLength(int index, int wheel) const
|
||||
{ return m_all_physic_info[index].m_suspension_length[wheel]; }
|
||||
// ------------------------------------------------------------------------
|
||||
void addReplayEvent(float time,
|
||||
const btTransform &trans,
|
||||
const ReplayBase::PhysicInfo &pi,
|
||||
const ReplayBase::KartReplayEvent &kre);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart is a ghost (replay) kart. */
|
||||
virtual bool isGhostKart() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Ghost can't be hunted. */
|
||||
virtual bool isInvulnerable() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the speed of the kart in meters/second. */
|
||||
virtual float getSpeed() const;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void kartIsInRestNow() {};
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
}; // GhostKart
|
||||
|
@ -837,7 +837,7 @@ void Kart::finishedRace(float time, bool from_server)
|
||||
// it would trigger a race end again.
|
||||
if(m_finished_race) return;
|
||||
|
||||
if(!from_server)
|
||||
/* if(!from_server)
|
||||
{
|
||||
if(NetworkConfig::get()->isServer())
|
||||
{
|
||||
@ -851,7 +851,7 @@ void Kart::finishedRace(float time, bool from_server)
|
||||
return;
|
||||
}
|
||||
} // !from_server
|
||||
|
||||
*/
|
||||
m_finished_race = true;
|
||||
m_finish_time = time;
|
||||
m_controller->finishedRace(time);
|
||||
@ -889,9 +889,12 @@ void Kart::finishedRace(float time, bool from_server)
|
||||
{
|
||||
// Save for music handling in race result gui
|
||||
setRaceResult();
|
||||
setController(new EndController(this, m_controller));
|
||||
if(!isGhostKart())
|
||||
{
|
||||
setController(new EndController(this, m_controller));
|
||||
}
|
||||
// Skip animation if this kart is eliminated
|
||||
if (m_eliminated) return;
|
||||
if (m_eliminated || isGhostKart()) return;
|
||||
|
||||
m_kart_model->setAnimation(m_race_result ?
|
||||
KartModel::AF_WIN_START : KartModel::AF_LOSE_START);
|
||||
|
@ -64,6 +64,17 @@ class TerrainInfo;
|
||||
class Kart : public AbstractKart
|
||||
{
|
||||
friend class Skidding;
|
||||
protected:
|
||||
/** Offset of the graphical kart chassis from the physical chassis. */
|
||||
float m_graphical_y_offset;
|
||||
|
||||
/** The coordinates of the front of the kart, used to determine when a
|
||||
* new lap is triggered. */
|
||||
Vec3 m_xyz_front;
|
||||
|
||||
/** Is time flying activated */
|
||||
bool m_is_jumping;
|
||||
|
||||
private:
|
||||
/** Handles speed increase and capping due to powerup, terrain, ... */
|
||||
MaxSpeed *m_max_speed;
|
||||
@ -102,13 +113,6 @@ private:
|
||||
/** Current race position (1-num_karts). */
|
||||
int m_race_position;
|
||||
|
||||
/** The coordinates of the front of the kart, used to determine when a
|
||||
* new lap is triggered. */
|
||||
Vec3 m_xyz_front;
|
||||
|
||||
/** Offset of the graphical kart chassis from the physical chassis. */
|
||||
float m_graphical_y_offset;
|
||||
|
||||
/** True if the kart wins, false otherwise. */
|
||||
bool m_race_result;
|
||||
|
||||
@ -169,9 +173,6 @@ private:
|
||||
// Graphical effects
|
||||
// -----------------
|
||||
|
||||
/** Is time flying activated */
|
||||
bool m_is_jumping;
|
||||
|
||||
/** The shadow of a kart. */
|
||||
Shadow *m_shadow;
|
||||
|
||||
@ -430,7 +431,7 @@ public:
|
||||
virtual void showStarEffect(float t);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the terrain info oject. */
|
||||
TerrainInfo *getTerrainInfo() { return m_terrain_info; }
|
||||
virtual const TerrainInfo *getTerrainInfo() const { return m_terrain_info; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void setOnScreenText(const wchar_t *text);
|
||||
// ------------------------------------------------------------------------
|
||||
@ -447,6 +448,12 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set this kart race result. */
|
||||
void setRaceResult();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart is a ghost (replay) kart. */
|
||||
virtual bool isGhostKart() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart is jumping. */
|
||||
virtual bool isJumping() const { return m_is_jumping; };
|
||||
|
||||
}; // Kart
|
||||
|
||||
|
@ -717,6 +717,11 @@ void KartModel::setAnimation(AnimationFrameType type, bool play_non_loop)
|
||||
m_animated_node->setLoopMode(false);
|
||||
m_animated_node->setAnimationEndCallback(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Special animation not found, revert to default
|
||||
m_current_animation = AF_DEFAULT;
|
||||
}
|
||||
} // setAnimation
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -769,6 +774,14 @@ void KartModel::OnAnimationEnd(scene::IAnimatedMeshSceneNode *node)
|
||||
// ----------------------------------------------------------------------------
|
||||
void KartModel::setDefaultSuspension()
|
||||
{
|
||||
GhostKart* gk = dynamic_cast<GhostKart*>(m_kart);
|
||||
if (gk)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_default_physics_suspension[i] = gk->getSuspensionLength(0, i);
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i=0; i<m_kart->getVehicle()->getNumWheels(); i++)
|
||||
{
|
||||
const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i);
|
||||
@ -786,30 +799,45 @@ void KartModel::setDefaultSuspension()
|
||||
* \param suspension Suspension height for all four wheels.
|
||||
* \param speed The speed of the kart in meters/sec, used for the
|
||||
* speed-weighted objects' animations
|
||||
* \param gt_replay_index The index to get replay data, used by ghost kart
|
||||
*/
|
||||
void KartModel::update(float dt, float distance, float steer, float speed)
|
||||
void KartModel::update(float dt, float distance, float steer, float speed,
|
||||
int gt_replay_index)
|
||||
{
|
||||
core::vector3df wheel_steer(0, steer*30.0f, 0);
|
||||
|
||||
for(unsigned int i=0; i<4; i++)
|
||||
{
|
||||
if (!m_kart || !m_wheel_node[i]) continue;
|
||||
if (!m_kart || !m_wheel_node[i]) continue;
|
||||
#ifdef DEBUG
|
||||
if (UserConfigParams::m_physics_debug &&
|
||||
!dynamic_cast<GhostKart*>(m_kart) )
|
||||
{
|
||||
const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i);
|
||||
// Make wheels that are not touching the ground invisible
|
||||
m_wheel_node[i]->setVisible(wi.m_raycastInfo.m_isInContact);
|
||||
}
|
||||
if (UserConfigParams::m_physics_debug &&
|
||||
!m_kart->isGhostKart())
|
||||
{
|
||||
const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i);
|
||||
// Make wheels that are not touching the ground invisible
|
||||
m_wheel_node[i]->setVisible(wi.m_raycastInfo.m_isInContact);
|
||||
}
|
||||
#endif
|
||||
core::vector3df pos = m_wheel_graphics_position[i].toIrrVector();
|
||||
|
||||
const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i);
|
||||
float suspension_length = 0.0f;
|
||||
GhostKart* gk = dynamic_cast<GhostKart*>(m_kart);
|
||||
// Prevent using m_default_physics_suspension uninitialized
|
||||
if (gk && gt_replay_index == -1) break;
|
||||
|
||||
if (gk)
|
||||
{
|
||||
suspension_length = gk->getSuspensionLength(gt_replay_index, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
suspension_length = m_kart->getVehicle()->getWheelInfo(i).
|
||||
m_raycastInfo.m_suspensionLength;
|
||||
}
|
||||
|
||||
// Check documentation of Kart::updateGraphics for the following line
|
||||
pos.Y += m_default_physics_suspension[i]
|
||||
- wi.m_raycastInfo.m_suspensionLength
|
||||
- suspension_length
|
||||
- m_kart_lowest_point;
|
||||
m_wheel_node[i]->setPosition(pos);
|
||||
|
||||
|
@ -237,8 +237,8 @@ public:
|
||||
void loadInfo(const XMLNode &node);
|
||||
bool loadModels(const KartProperties &kart_properties);
|
||||
void setDefaultSuspension();
|
||||
void update(float dt, float distance, float steer,
|
||||
float speed);
|
||||
void update(float dt, float distance, float steer, float speed,
|
||||
int gt_replay_index = -1);
|
||||
void finishedRace();
|
||||
scene::ISceneNode*
|
||||
attachModel(bool animatedModels, bool always_animated);
|
||||
|
@ -23,7 +23,6 @@
|
||||
#endif
|
||||
#include "achievements/achievement_info.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
#include "karts/ghost_kart.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/kart_gfx.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
@ -82,7 +81,7 @@ void Skidding::reset()
|
||||
|
||||
btVector3 rot(0, 0, 0);
|
||||
// Only access the vehicle if the kart is not a ghost
|
||||
if (dynamic_cast<GhostKart*>(m_kart)==NULL)
|
||||
if (!m_kart->isGhostKart())
|
||||
m_kart->getVehicle()->setTimedRotation(0, rot);
|
||||
} // reset
|
||||
|
||||
|
@ -527,7 +527,6 @@ void cmdLineHelp()
|
||||
" spaces are allowed in the track names.\n"
|
||||
" --demo-laps=n Number of laps in a demo.\n"
|
||||
" --demo-karts=n Number of karts to use in a demo.\n"
|
||||
" --ghost Replay ghost data together with one player kart.\n"
|
||||
// " --history Replay history file 'history.dat'.\n"
|
||||
// " --history=n Replay history file 'history.dat' using:\n"
|
||||
// " n=1: recorded positions\n"
|
||||
@ -1004,9 +1003,6 @@ int handleCmdLine()
|
||||
}
|
||||
} // --with-profile
|
||||
|
||||
if(CommandLine::has("--ghost"))
|
||||
ReplayPlay::create();
|
||||
|
||||
if(CommandLine::has("--history", &n))
|
||||
{
|
||||
history->doReplayHistory( (History::HistoryReplayMode)n);
|
||||
@ -1157,6 +1153,7 @@ void initRest()
|
||||
// The order here can be important, e.g. KartPropertiesManager needs
|
||||
// defaultKartProperties, which are defined in stk_config.
|
||||
history = new History ();
|
||||
ReplayPlay::create();
|
||||
ReplayRecorder::create();
|
||||
material_manager = new MaterialManager ();
|
||||
track_manager = new TrackManager ();
|
||||
@ -1581,7 +1578,6 @@ static void cleanSuperTuxKart()
|
||||
irr_driver->updateConfigIfRelevant();
|
||||
AchievementsManager::destroy();
|
||||
Referee::cleanup();
|
||||
if(ReplayPlay::get()) ReplayPlay::destroy();
|
||||
if(race_manager) delete race_manager;
|
||||
if(grand_prix_manager) delete grand_prix_manager;
|
||||
if(highscore_manager) delete highscore_manager;
|
||||
@ -1593,6 +1589,7 @@ static void cleanSuperTuxKart()
|
||||
if(track_manager) delete track_manager;
|
||||
if(material_manager) delete material_manager;
|
||||
if(history) delete history;
|
||||
ReplayPlay::destroy();
|
||||
ReplayRecorder::destroy();
|
||||
delete ParticleKindManager::get();
|
||||
PlayerManager::destroy();
|
||||
|
@ -46,20 +46,20 @@ public:
|
||||
EasterEggHunt();
|
||||
virtual ~EasterEggHunt();
|
||||
|
||||
virtual void init();
|
||||
virtual void init() OVERRIDE;
|
||||
|
||||
virtual bool isRaceOver();
|
||||
virtual bool isRaceOver() OVERRIDE;
|
||||
|
||||
// overriding World methods
|
||||
virtual void reset();
|
||||
virtual void reset() OVERRIDE;
|
||||
|
||||
virtual bool raceHasLaps(){ return false; }
|
||||
virtual bool raceHasLaps() OVERRIDE { return false; }
|
||||
|
||||
virtual const std::string& getIdent() const;
|
||||
virtual void terminateRace();
|
||||
virtual void update(float dt);
|
||||
virtual const std::string& getIdent() const OVERRIDE;
|
||||
virtual void terminateRace() OVERRIDE;
|
||||
virtual void update(float dt) OVERRIDE;
|
||||
virtual void getKartsDisplayInfo(
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info);
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
|
||||
|
||||
void updateKartRanks();
|
||||
void collectedEasterEgg(const AbstractKart *kart);
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
// overriding World methods
|
||||
virtual void reset() OVERRIDE;
|
||||
virtual const std::string& getIdent() const OVERRIDE;
|
||||
virtual const btTransform &getStartTransform(int index);
|
||||
virtual const btTransform &getStartTransform(int index) OVERRIDE;
|
||||
virtual float getClockStartTime() const;
|
||||
virtual void getKartsDisplayInfo(
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
|
||||
|
@ -178,9 +178,10 @@ void LinearWorld::update(float dt)
|
||||
// in the position of the kart (e.g. while falling the kart
|
||||
// might get too close to another part of the track, shortly
|
||||
// jump to position one, then on reset fall back to last)
|
||||
if (!kart_info.getTrackSector()->isOnRoad() &&
|
||||
if ((!kart_info.getTrackSector()->isOnRoad() &&
|
||||
(!kart->getMaterial() ||
|
||||
kart->getMaterial()->isDriveReset()) )
|
||||
kart->getMaterial()->isDriveReset())) &&
|
||||
!kart->isGhostKart())
|
||||
continue;
|
||||
kart_info.getTrackSector()->update(kart->getFrontXYZ());
|
||||
kart_info.m_overall_distance = kart_info.m_race_lap
|
||||
|
@ -160,7 +160,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of laps a kart has completed.
|
||||
* \param kart_index World index of the kart. */
|
||||
int getKartLaps(unsigned int kart_index) const
|
||||
int getKartLaps(unsigned int kart_index) const OVERRIDE
|
||||
{
|
||||
assert(kart_index < m_kart_info.size());
|
||||
return m_kart_info[kart_index].m_race_lap;
|
||||
|
@ -37,7 +37,7 @@ class OverWorld : public WorldWithRank
|
||||
protected:
|
||||
|
||||
/** Override from base class */
|
||||
virtual void createRaceGUI();
|
||||
virtual void createRaceGUI() OVERRIDE;
|
||||
|
||||
bool m_return_to_garage;
|
||||
|
||||
|
@ -50,7 +50,7 @@ protected:
|
||||
virtual AbstractKart *createKart(const std::string &kart_ident, int index,
|
||||
int local_player_id, int global_player_id,
|
||||
RaceManager::KartType type,
|
||||
PerPlayerDifficulty difficulty);
|
||||
PerPlayerDifficulty difficulty) OVERRIDE;
|
||||
|
||||
private:
|
||||
/** Keep a pointer to the track object of soccer ball */
|
||||
@ -113,27 +113,27 @@ public:
|
||||
SoccerWorld();
|
||||
virtual ~SoccerWorld();
|
||||
|
||||
virtual void init();
|
||||
virtual void init() OVERRIDE;
|
||||
|
||||
// clock events
|
||||
virtual bool isRaceOver();
|
||||
virtual void terminateRace();
|
||||
virtual bool isRaceOver() OVERRIDE;
|
||||
virtual void terminateRace() OVERRIDE;
|
||||
virtual void countdownReachedZero() OVERRIDE;
|
||||
|
||||
// overriding World methods
|
||||
virtual void reset();
|
||||
virtual void reset() OVERRIDE;
|
||||
|
||||
virtual unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE;
|
||||
|
||||
virtual bool useFastMusicNearEnd() const { return false; }
|
||||
virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
|
||||
virtual void getKartsDisplayInfo(
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) {}
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE {}
|
||||
|
||||
virtual bool raceHasLaps() { return false; }
|
||||
virtual bool raceHasLaps() OVERRIDE { return false; }
|
||||
|
||||
virtual const std::string& getIdent() const;
|
||||
virtual const std::string& getIdent() const OVERRIDE;
|
||||
|
||||
virtual void update(float dt);
|
||||
virtual void update(float dt) OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
void onCheckGoalTriggered(bool first_goal);
|
||||
// ------------------------------------------------------------------------
|
||||
@ -157,23 +157,23 @@ public:
|
||||
m_blue_score_times : m_red_score_times);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
const int& getKartNode(unsigned int kart_id) const
|
||||
const int getKartNode(unsigned int kart_id) const
|
||||
{ return m_kart_on_node[kart_id]; }
|
||||
// ------------------------------------------------------------------------
|
||||
const int& getBallNode() const
|
||||
const int getBallNode() const
|
||||
{ return m_ball_on_node; }
|
||||
// ------------------------------------------------------------------------
|
||||
const Vec3& getBallPosition() const
|
||||
{ return m_ball_position; }
|
||||
// ------------------------------------------------------------------------
|
||||
const int& getGoalNode(SoccerTeam team) const
|
||||
const int getGoalNode(SoccerTeam team) const
|
||||
{
|
||||
return (team == SOCCER_TEAM_BLUE ? m_blue_goal_node : m_red_goal_node);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
bool isCorrectGoal(unsigned int kart_id, bool first_goal) const;
|
||||
// ------------------------------------------------------------------------
|
||||
const int& getDefender(SoccerTeam team) const
|
||||
const int getDefender(SoccerTeam team) const
|
||||
{
|
||||
return (team == SOCCER_TEAM_BLUE ? m_blue_defender : m_red_defender);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class StandardRace : public LinearWorld
|
||||
{
|
||||
protected:
|
||||
// clock events
|
||||
virtual bool isRaceOver();
|
||||
virtual bool isRaceOver() OVERRIDE;
|
||||
|
||||
public:
|
||||
StandardRace();
|
||||
|
@ -146,6 +146,9 @@ void World::init()
|
||||
m_eliminated_karts = 0;
|
||||
m_eliminated_players = 0;
|
||||
m_num_players = 0;
|
||||
unsigned int gk = 0;
|
||||
if (race_manager->hasGhostKarts())
|
||||
gk = ReplayPlay::get()->getNumGhostKart();
|
||||
|
||||
// Create the race gui before anything else is attached to the scene node
|
||||
// (which happens when the track is loaded). This allows the race gui to
|
||||
@ -179,8 +182,16 @@ void World::init()
|
||||
// karts can be positioned properly on (and not in) the tracks.
|
||||
m_track->loadTrackModel(race_manager->getReverseTrack());
|
||||
|
||||
if (gk > 0)
|
||||
{
|
||||
ReplayPlay::get()->load();
|
||||
for (unsigned int k = 0; k < gk; k++)
|
||||
m_karts.push_back(ReplayPlay::get()->getGhostKart(k));
|
||||
}
|
||||
|
||||
for(unsigned int i=0; i<num_karts; i++)
|
||||
{
|
||||
if (race_manager->getKartType(i) == RaceManager::KT_GHOST) continue;
|
||||
std::string kart_ident = history->replayHistory()
|
||||
? history->getKartIdent(i)
|
||||
: race_manager->getKartIdent(i);
|
||||
@ -201,9 +212,6 @@ void World::init()
|
||||
// Must be called after all karts are created
|
||||
m_race_gui->init();
|
||||
|
||||
if(ReplayPlay::get())
|
||||
ReplayPlay::get()->Load();
|
||||
|
||||
powerup_manager->updateWeightsForRace(num_karts);
|
||||
|
||||
if (UserConfigParams::m_weather_effects)
|
||||
@ -249,7 +257,7 @@ void World::reset()
|
||||
Camera::getCamera(i)->reset();
|
||||
}
|
||||
|
||||
if(ReplayPlay::get())
|
||||
if(race_manager->hasGhostKarts())
|
||||
ReplayPlay::get()->reset();
|
||||
|
||||
resetAllKarts();
|
||||
@ -271,7 +279,11 @@ void World::reset()
|
||||
race_manager->reset();
|
||||
// Make sure to overwrite the data from the previous race.
|
||||
if(!history->replayHistory()) history->initRecording();
|
||||
if(ReplayRecorder::get()) ReplayRecorder::get()->init();
|
||||
if(race_manager->willRecordRace())
|
||||
{
|
||||
Log::info("World", "Start Recording race.");
|
||||
ReplayRecorder::get()->init();
|
||||
}
|
||||
|
||||
// Reset all data structures that depend on number of karts.
|
||||
irr_driver->reset();
|
||||
@ -381,16 +393,6 @@ World::~World()
|
||||
{
|
||||
irr_driver->onUnloadWorld();
|
||||
|
||||
if(ReplayPlay::get())
|
||||
{
|
||||
// Destroy the old replay object, which also stored the ghost
|
||||
// karts, and create a new one (which means that in further
|
||||
// races the usage of ghosts will still be enabled).
|
||||
ReplayPlay::destroy();
|
||||
ReplayPlay::create();
|
||||
}
|
||||
|
||||
|
||||
// In case that a race is aborted (e.g. track not found) m_track is 0.
|
||||
if(m_track)
|
||||
m_track->cleanup();
|
||||
@ -415,9 +417,24 @@ World::~World()
|
||||
delete m_weather;
|
||||
|
||||
for ( unsigned int i = 0 ; i < m_karts.size() ; i++ )
|
||||
{
|
||||
// Let ReplayPlay destroy the ghost karts
|
||||
if (m_karts[i]->isGhostKart()) continue;
|
||||
delete m_karts[i];
|
||||
}
|
||||
|
||||
if(race_manager->hasGhostKarts())
|
||||
{
|
||||
// Destroy the old replay object, which also stored the ghost
|
||||
// karts, and create a new one (which means that in further
|
||||
// races the usage of ghosts will still be enabled).
|
||||
ReplayPlay::destroy();
|
||||
ReplayPlay::create();
|
||||
}
|
||||
m_karts.clear();
|
||||
race_manager->setRaceGhostKarts(false);
|
||||
race_manager->setRecordRace(false);
|
||||
|
||||
Camera::removeAllCameras();
|
||||
|
||||
projectile_manager->cleanup();
|
||||
@ -446,6 +463,7 @@ void World::onGo()
|
||||
// from sliding downhill)
|
||||
for(unsigned int i=0; i<m_karts.size(); i++)
|
||||
{
|
||||
if (m_karts[i]->isGhostKart()) continue;
|
||||
m_karts[i]->getVehicle()->setAllBrakes(0);
|
||||
}
|
||||
} // onGo
|
||||
@ -586,12 +604,13 @@ void World::resetAllKarts()
|
||||
getPhysics()->getPhysicsWorld()->resetLocalTime();
|
||||
|
||||
// If track checking is requested, check all rescue positions if
|
||||
// they are heigh enough.
|
||||
// they are high enough.
|
||||
if(UserConfigParams::m_track_debug)
|
||||
{
|
||||
// Loop over all karts, in case that some karts are dfferent
|
||||
for(unsigned int kart_id=0; kart_id<(unsigned int)m_karts.size(); kart_id++)
|
||||
{
|
||||
if (m_karts[kart_id]->isGhostKart()) continue;
|
||||
for(unsigned int rescue_pos=0;
|
||||
rescue_pos<getNumberOfRescuePositions();
|
||||
rescue_pos++)
|
||||
@ -619,6 +638,7 @@ void World::resetAllKarts()
|
||||
//that at least one of its wheel will be on the surface of the track
|
||||
for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++)
|
||||
{
|
||||
if ((*i)->isGhostKart()) continue;
|
||||
Vec3 xyz = (*i)->getXYZ();
|
||||
//start projection from top of kart
|
||||
Vec3 up_offset(0, 0.5f * ((*i)->getKartHeight()), 0);
|
||||
@ -667,6 +687,7 @@ void World::resetAllKarts()
|
||||
all_finished=true;
|
||||
for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++)
|
||||
{
|
||||
if ((*i)->isGhostKart()) continue;
|
||||
if(!(*i)->isInRest())
|
||||
{
|
||||
Vec3 normal;
|
||||
@ -945,8 +966,7 @@ void World::update(float dt)
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("World::update (sub-updates)", 0x20, 0x7F, 0x00);
|
||||
history->update(dt);
|
||||
if(ReplayRecorder::get()) ReplayRecorder::get()->update(dt);
|
||||
if(ReplayPlay::get()) ReplayPlay::get()->update(dt);
|
||||
if(race_manager->willRecordRace()) ReplayRecorder::get()->update(dt);
|
||||
if(history->replayHistory()) dt=history->getNextDelta();
|
||||
WorldStatus::update(dt);
|
||||
if (m_script_engine) m_script_engine->update(dt);
|
||||
@ -1146,6 +1166,7 @@ AbstractKart *World::getLocalPlayerKart(unsigned int n) const
|
||||
void World::eliminateKart(int kart_id, bool notify_of_elimination)
|
||||
{
|
||||
AbstractKart *kart = m_karts[kart_id];
|
||||
if (kart->isGhostKart()) return;
|
||||
|
||||
// Display a message about the eliminated kart in the race guia
|
||||
if (notify_of_elimination)
|
||||
|
@ -175,7 +175,7 @@ protected:
|
||||
Weather* m_weather;
|
||||
|
||||
|
||||
virtual void onGo();
|
||||
virtual void onGo() OVERRIDE;
|
||||
/** Returns true if the race is over. Must be defined by all modes. */
|
||||
virtual bool isRaceOver() = 0;
|
||||
virtual void update(float dt);
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
/** call just after instanciating. can't be moved to the contructor as child
|
||||
classes must be instanciated, otherwise polymorphism will fail and the
|
||||
results will be incorrect */
|
||||
virtual void init();
|
||||
virtual void init() OVERRIDE;
|
||||
|
||||
bool displayRank() const { return m_display_rank; }
|
||||
|
||||
|
@ -172,10 +172,10 @@ void Network::broadcastPacket(NetworkString *data, bool reliable)
|
||||
void Network::openLog()
|
||||
{
|
||||
m_log_file.setAtomic(NULL);
|
||||
if (UserConfigParams::m_packets_log_filename.toString() != "")
|
||||
if (UserConfigParams::m_log_packets)
|
||||
{
|
||||
std::string s = file_manager
|
||||
->getUserConfigFile(UserConfigParams::m_packets_log_filename);
|
||||
->getUserConfigFile(FileManager::getStdoutName()+".packet");
|
||||
m_log_file.setAtomic(fopen(s.c_str(), "w+"));
|
||||
}
|
||||
if (!m_log_file.getData())
|
||||
@ -198,8 +198,10 @@ void Network::logPacket(const BareNetworkString &ns, bool incoming)
|
||||
m_log_file.lock();
|
||||
fprintf(m_log_file.getData(), "[%d\t] %s ",
|
||||
(int)(StkTime::getRealTime()), arrow);
|
||||
|
||||
fprintf(m_log_file.getData(), ns.getLogMessage().c_str());
|
||||
// Indentation for all lines after the first, so that the dump
|
||||
// is nicely aligned.
|
||||
std::string indent(" ");
|
||||
fprintf(m_log_file.getData(), "%s", ns.getLogMessage(indent).c_str());
|
||||
m_log_file.unlock();
|
||||
} // logPacket
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -171,9 +171,3 @@ void NetworkConsole::kickAllPlayers()
|
||||
peers[i]->disconnect();
|
||||
}
|
||||
} // kickAllPlayers
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkConsole::sendPacket(NetworkString *data, bool reliable)
|
||||
{
|
||||
m_localhost->broadcastPacket(data, reliable);
|
||||
} // sendPacket
|
||||
|
@ -44,8 +44,6 @@ public:
|
||||
|
||||
virtual void run();
|
||||
void kickAllPlayers();
|
||||
virtual void sendPacket(NetworkString *data,
|
||||
bool reliable = true);
|
||||
// ------------------------------------------------------------------------
|
||||
void setMaxPlayers(uint8_t count) { m_max_players = count; }
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -128,7 +128,7 @@ int BareNetworkString::decodeStringW(int pos, irr::core::stringw *out) const
|
||||
* to stdout or via the Log mechanism. Format
|
||||
* 0000 : 1234 5678 9abc ... ASCII-
|
||||
*/
|
||||
std::string BareNetworkString::getLogMessage() const
|
||||
std::string BareNetworkString::getLogMessage(const std::string &indent) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
for(unsigned int line=0; line<m_buffer.size(); line+=16)
|
||||
@ -154,12 +154,18 @@ std::string BareNetworkString::getLogMessage() const
|
||||
for(unsigned int i=line; i<upper_limit; i++)
|
||||
{
|
||||
uint8_t c = m_buffer[i];
|
||||
if(isprint(c) && c!=0x09) // Don't print tabs
|
||||
// Don't print tabs, and characters >=128, which are often shown
|
||||
// as more than one character.
|
||||
if(isprint(c) && c!=0x09 && c<=0x80)
|
||||
oss << char(c);
|
||||
else
|
||||
oss << '.';
|
||||
} // for i
|
||||
oss << "\n";
|
||||
// If it's not the last line, add the indentation in front
|
||||
// of the next line
|
||||
if(line+16<m_buffer.size())
|
||||
oss << indent;
|
||||
} // for line
|
||||
|
||||
return oss.str();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user