mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 13:35:12 +00:00
Add networking for custom behaviors
This commit is contained in:
parent
9c7036afe3
commit
a87116a632
11 changed files with 307 additions and 5 deletions
|
@ -39,6 +39,7 @@ in_files = [
|
|||
"src/game/object_helpers.c",
|
||||
"src/game/obj_behaviors.c",
|
||||
"src/game/obj_behaviors_2.c",
|
||||
"src/game/spawn_sound.c",
|
||||
]
|
||||
|
||||
override_allowed_functions = {
|
||||
|
@ -69,6 +70,7 @@ override_disallowed_functions = {
|
|||
"src/game/object_helpers.c": [ "spawn_obj", "^bhv_", "abs[fi]", "^bit_shift", "_debug$", "^stub_" ],
|
||||
"src/game/obj_behaviors.c": [ "debug_" ],
|
||||
"src/game/obj_behaviors_2.c": [ "wiggler_jumped_on_attack_handler", "huge_goomba_weakly_attacked" ],
|
||||
"src/game/spawn_sound.c": [ "spawner" ],
|
||||
}
|
||||
|
||||
lua_function_params = {
|
||||
|
|
|
@ -16,6 +16,7 @@ in_files = [
|
|||
'src/game/object_helpers.h',
|
||||
'src/game/mario_step.h',
|
||||
'src/pc/lua/smlua_anim_utils.h',
|
||||
'src/game/spawn_sound.h',
|
||||
]
|
||||
|
||||
smlua_cobject_autogen = 'src/pc/lua/smlua_cobject_autogen'
|
||||
|
|
|
@ -644,6 +644,15 @@
|
|||
|
||||
<br />
|
||||
|
||||
- spawn_sound.c
|
||||
- [calc_dist_to_volume_range_1](#calc_dist_to_volume_range_1)
|
||||
- [calc_dist_to_volume_range_2](#calc_dist_to_volume_range_2)
|
||||
- [cur_obj_play_sound_1](#cur_obj_play_sound_1)
|
||||
- [cur_obj_play_sound_2](#cur_obj_play_sound_2)
|
||||
- [exec_anim_sound_state](#exec_anim_sound_state)
|
||||
|
||||
<br />
|
||||
|
||||
- surface_collision.h
|
||||
- [find_ceil_height](#find_ceil_height)
|
||||
- [find_floor_height](#find_floor_height)
|
||||
|
@ -11843,6 +11852,112 @@
|
|||
|
||||
<br />
|
||||
|
||||
---
|
||||
# functions from spawn_sound.c
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
## [calc_dist_to_volume_range_1](#calc_dist_to_volume_range_1)
|
||||
|
||||
### Lua Example
|
||||
`local integerValue = calc_dist_to_volume_range_1(distance)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| distance | number |
|
||||
|
||||
### Returns
|
||||
- integer
|
||||
|
||||
### C Prototype
|
||||
`s32 calc_dist_to_volume_range_1(f32 distance);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [calc_dist_to_volume_range_2](#calc_dist_to_volume_range_2)
|
||||
|
||||
### Lua Example
|
||||
`local integerValue = calc_dist_to_volume_range_2(distance)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| distance | number |
|
||||
|
||||
### Returns
|
||||
- integer
|
||||
|
||||
### C Prototype
|
||||
`s32 calc_dist_to_volume_range_2(f32 distance);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [cur_obj_play_sound_1](#cur_obj_play_sound_1)
|
||||
|
||||
### Lua Example
|
||||
`cur_obj_play_sound_1(soundMagic)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| soundMagic | integer |
|
||||
|
||||
### Returns
|
||||
- None
|
||||
|
||||
### C Prototype
|
||||
`void cur_obj_play_sound_1(s32 soundMagic);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [cur_obj_play_sound_2](#cur_obj_play_sound_2)
|
||||
|
||||
### Lua Example
|
||||
`cur_obj_play_sound_2(soundMagic)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| soundMagic | integer |
|
||||
|
||||
### Returns
|
||||
- None
|
||||
|
||||
### C Prototype
|
||||
`void cur_obj_play_sound_2(s32 soundMagic);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [exec_anim_sound_state](#exec_anim_sound_state)
|
||||
|
||||
### Lua Example
|
||||
`exec_anim_sound_state(soundStates)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| soundStates | [SoundState](structs.md#SoundState) |
|
||||
|
||||
### Returns
|
||||
- None
|
||||
|
||||
### C Prototype
|
||||
`void exec_anim_sound_state(struct SoundState *soundStates);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
# functions from surface_collision.h
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
- [PlayerCameraState](#PlayerCameraState)
|
||||
- [PlayerGeometry](#PlayerGeometry)
|
||||
- [SPTask](#SPTask)
|
||||
- [SoundState](#SoundState)
|
||||
- [SpawnInfo](#SpawnInfo)
|
||||
- [SpawnParticlesInfo](#SpawnParticlesInfo)
|
||||
- [Struct802A272C](#Struct802A272C)
|
||||
|
@ -1603,6 +1604,19 @@
|
|||
|
||||
<br />
|
||||
|
||||
## [SoundState](#SoundState)
|
||||
|
||||
| Field | Type | Access |
|
||||
| ----- | ---- | ------ |
|
||||
| animFrame1 | integer | |
|
||||
| animFrame2 | integer | |
|
||||
| playSound | integer | |
|
||||
| soundMagic | integer | |
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [SpawnInfo](#SpawnInfo)
|
||||
|
||||
| Field | Type | Access |
|
||||
|
|
|
@ -30,7 +30,7 @@ struct LuaObjectTable sLuaObjectTable[LOT_MAX] = {
|
|||
{ LOT_VEC3F, sVec3fFields, LUA_VEC3F_FIELD_COUNT },
|
||||
};
|
||||
|
||||
static struct LuaObjectField* smlua_get_object_field(u16 lot, const char* key) {
|
||||
struct LuaObjectField* smlua_get_object_field(u16 lot, const char* key) {
|
||||
if (lot > LOT_AUTOGEN_MIN) {
|
||||
return smlua_get_object_field_autogen(lot, key);
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ static int smlua_func_define_custom_obj_fields(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static struct LuaObjectField* smlua_get_custom_field(lua_State* L, u32 lot, int keyIndex) {
|
||||
struct LuaObjectField* smlua_get_custom_field(lua_State* L, u32 lot, int keyIndex) {
|
||||
LUA_STACK_CHECK_BEGIN();
|
||||
static struct LuaObjectField lof = { 0 };
|
||||
if (lot != LOT_OBJECT) { return NULL; }
|
||||
|
|
|
@ -54,6 +54,8 @@ struct LuaObjectTable {
|
|||
|
||||
bool smlua_valid_lot(u16 lot);
|
||||
bool smlua_valid_lvt(u16 lvt);
|
||||
struct LuaObjectField* smlua_get_object_field(u16 lot, const char* key);
|
||||
struct LuaObjectField* smlua_get_custom_field(lua_State* L, u32 lot, int keyIndex);
|
||||
void smlua_cobject_init_globals(void);
|
||||
void smlua_cobject_init_per_file_globals(char* path);
|
||||
void smlua_bind_cobject(void);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "src/game/object_helpers.h"
|
||||
#include "src/game/mario_step.h"
|
||||
#include "src/pc/lua/smlua_anim_utils.h"
|
||||
#include "src/game/spawn_sound.h"
|
||||
|
||||
#include "include/object_fields.h"
|
||||
|
||||
|
@ -1403,6 +1404,14 @@ static struct LuaObjectField sPlayerGeometryFields[LUA_PLAYER_GEOMETRY_FIELD_COU
|
|||
{ "waterHeight", LVT_F32, offsetof(struct PlayerGeometry, waterHeight), false, LOT_NONE },
|
||||
};
|
||||
|
||||
#define LUA_SOUND_STATE_FIELD_COUNT 4
|
||||
static struct LuaObjectField sSoundStateFields[LUA_SOUND_STATE_FIELD_COUNT] = {
|
||||
{ "animFrame1", LVT_S8, offsetof(struct SoundState, animFrame1), false, LOT_NONE },
|
||||
{ "animFrame2", LVT_S8, offsetof(struct SoundState, animFrame2), false, LOT_NONE },
|
||||
{ "playSound", LVT_S16, offsetof(struct SoundState, playSound), false, LOT_NONE },
|
||||
{ "soundMagic", LVT_S32, offsetof(struct SoundState, soundMagic), false, LOT_NONE },
|
||||
};
|
||||
|
||||
#define LUA_SPAWN_INFO_FIELD_COUNT 7
|
||||
static struct LuaObjectField sSpawnInfoFields[LUA_SPAWN_INFO_FIELD_COUNT] = {
|
||||
{ "activeAreaIndex", LVT_S8, offsetof(struct SpawnInfo, activeAreaIndex), false, LOT_NONE },
|
||||
|
@ -1590,6 +1599,7 @@ struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN]
|
|||
{ LOT_PARALLELTRACKINGPOINT, sParallelTrackingPointFields, LUA_PARALLEL_TRACKING_POINT_FIELD_COUNT },
|
||||
{ LOT_PLAYERCAMERASTATE, sPlayerCameraStateFields, LUA_PLAYER_CAMERA_STATE_FIELD_COUNT },
|
||||
{ LOT_PLAYERGEOMETRY, sPlayerGeometryFields, LUA_PLAYER_GEOMETRY_FIELD_COUNT },
|
||||
{ LOT_SOUNDSTATE, sSoundStateFields, LUA_SOUND_STATE_FIELD_COUNT },
|
||||
{ LOT_SPAWNINFO, sSpawnInfoFields, LUA_SPAWN_INFO_FIELD_COUNT },
|
||||
{ LOT_SPAWNPARTICLESINFO, sSpawnParticlesInfoFields, LUA_SPAWN_PARTICLES_INFO_FIELD_COUNT },
|
||||
{ LOT_STRUCT802A272C, sStruct802A272CFields, LUA_STRUCT802_A272_C_FIELD_COUNT },
|
||||
|
|
|
@ -42,6 +42,7 @@ enum LuaObjectAutogenType {
|
|||
LOT_PARALLELTRACKINGPOINT,
|
||||
LOT_PLAYERCAMERASTATE,
|
||||
LOT_PLAYERGEOMETRY,
|
||||
LOT_SOUNDSTATE,
|
||||
LOT_SPAWNINFO,
|
||||
LOT_SPAWNPARTICLESINFO,
|
||||
LOT_STRUCT802A272C,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "smlua.h"
|
||||
#include "smlua_cobject.h"
|
||||
|
||||
#include "game/level_update.h"
|
||||
#include "game/area.h"
|
||||
|
@ -79,6 +80,83 @@ int smlua_func_init_mario_after_warp(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_network_init_object(lua_State* L) {
|
||||
if (!smlua_functions_valid_param_count(L, 3)) { return 0; }
|
||||
|
||||
struct Object* obj = smlua_to_cobject(L, 1, LOT_OBJECT);
|
||||
if (!gSmLuaConvertSuccess || obj == NULL) { return 0; }
|
||||
|
||||
bool standardSync = smlua_to_boolean(L, 2);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
if (lua_type(L, 3) != LUA_TNIL && lua_type(L, 3) != LUA_TTABLE) {
|
||||
LOG_LUA("network_init_object() called with an invalid type for param 3: %u", lua_type(L, 3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct SyncObject* so = network_init_object(obj, standardSync ? 4000.0f : SYNC_DISTANCE_ONLY_EVENTS);
|
||||
if (so == NULL) {
|
||||
LOG_LUA("Failed to allocate sync object.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lua_type(L, 3) == LUA_TTABLE) {
|
||||
lua_pushnil(L); // first key
|
||||
|
||||
while (lua_next(L, 3) != 0) {
|
||||
// uses 'key' (at index -2) and 'value' (at index -1)
|
||||
if (lua_type(L, -1) != LUA_TSTRING) {
|
||||
LOG_LUA("Invalid type passed to network_init_object(): %u", lua_type(L, -1));
|
||||
lua_pop(L, 1); // pop value
|
||||
continue;
|
||||
}
|
||||
const char* fieldIdentifier = smlua_to_string(L, -1);
|
||||
if (!gSmLuaConvertSuccess || fieldIdentifier[0] != 'o') {
|
||||
LOG_LUA("Invalid field passed to network_init_object()");
|
||||
lua_pop(L, 1); // pop value
|
||||
continue;
|
||||
}
|
||||
|
||||
struct LuaObjectField* data = smlua_get_object_field(LOT_OBJECT, fieldIdentifier);
|
||||
if (data == NULL) {
|
||||
data = smlua_get_custom_field(L, LOT_OBJECT, lua_gettop(L));
|
||||
}
|
||||
if (data == NULL) {
|
||||
LOG_LUA("Invalid field passed to network_init_object(): %s", fieldIdentifier);
|
||||
lua_pop(L, 1); // pop value
|
||||
continue;
|
||||
}
|
||||
|
||||
u8* field = ((u8*)(intptr_t)obj) + data->valueOffset;
|
||||
network_init_object_field(obj, field);
|
||||
|
||||
lua_pop(L, 1); // pop value
|
||||
}
|
||||
lua_pop(L, 1); // pop key
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_network_send_object(lua_State* L) {
|
||||
if (!smlua_functions_valid_param_count(L, 2)) { return 0; }
|
||||
|
||||
struct Object* obj = smlua_to_cobject(L, 1, LOT_OBJECT);
|
||||
if (!gSmLuaConvertSuccess || obj == NULL) { return 0; }
|
||||
|
||||
bool reliable = smlua_to_boolean(L, 2);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
if (obj->oSyncID == 0 || gSyncObjects[obj->oSyncID].o != obj) {
|
||||
LOG_LUA("Failed to retrieve sync object.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
network_send_object_reliability(obj, reliable);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//////////
|
||||
// bind //
|
||||
//////////
|
||||
|
@ -91,4 +169,6 @@ void smlua_bind_functions(void) {
|
|||
smlua_bind_function(L, "coss", smlua_func_coss);
|
||||
smlua_bind_function(L, "atan2s", smlua_func_atan2s);
|
||||
smlua_bind_function(L, "init_mario_after_warp", smlua_func_init_mario_after_warp);
|
||||
smlua_bind_function(L, "network_init_object", smlua_func_network_init_object);
|
||||
smlua_bind_function(L, "network_send_object", smlua_func_network_send_object);
|
||||
}
|
|
@ -7582,6 +7582,70 @@ int smlua_func_stop_shell_music(UNUSED lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// spawn_sound.c //
|
||||
///////////////////
|
||||
|
||||
int smlua_func_calc_dist_to_volume_range_1(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
|
||||
|
||||
f32 distance = smlua_to_number(L, 1);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
extern s32 calc_dist_to_volume_range_1(f32 distance);
|
||||
lua_pushinteger(L, calc_dist_to_volume_range_1(distance));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_calc_dist_to_volume_range_2(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
|
||||
|
||||
f32 distance = smlua_to_number(L, 1);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
extern s32 calc_dist_to_volume_range_2(f32 distance);
|
||||
lua_pushinteger(L, calc_dist_to_volume_range_2(distance));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_cur_obj_play_sound_1(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
|
||||
|
||||
s32 soundMagic = smlua_to_integer(L, 1);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
extern void cur_obj_play_sound_1(s32 soundMagic);
|
||||
cur_obj_play_sound_1(soundMagic);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_cur_obj_play_sound_2(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
|
||||
|
||||
s32 soundMagic = smlua_to_integer(L, 1);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
extern void cur_obj_play_sound_2(s32 soundMagic);
|
||||
cur_obj_play_sound_2(soundMagic);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_exec_anim_sound_state(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
|
||||
|
||||
struct SoundState* soundStates = (struct SoundState*)smlua_to_cobject(L, 1, LOT_SOUNDSTATE);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
extern void exec_anim_sound_state(struct SoundState *soundStates);
|
||||
exec_anim_sound_state(soundStates);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// surface_collision.h //
|
||||
/////////////////////////
|
||||
|
@ -8422,6 +8486,13 @@ void smlua_bind_functions_autogen(void) {
|
|||
smlua_bind_function(L, "stop_cap_music", smlua_func_stop_cap_music);
|
||||
smlua_bind_function(L, "stop_shell_music", smlua_func_stop_shell_music);
|
||||
|
||||
// spawn_sound.c
|
||||
smlua_bind_function(L, "calc_dist_to_volume_range_1", smlua_func_calc_dist_to_volume_range_1);
|
||||
smlua_bind_function(L, "calc_dist_to_volume_range_2", smlua_func_calc_dist_to_volume_range_2);
|
||||
smlua_bind_function(L, "cur_obj_play_sound_1", smlua_func_cur_obj_play_sound_1);
|
||||
smlua_bind_function(L, "cur_obj_play_sound_2", smlua_func_cur_obj_play_sound_2);
|
||||
smlua_bind_function(L, "exec_anim_sound_state", smlua_func_exec_anim_sound_state);
|
||||
|
||||
// surface_collision.h
|
||||
//smlua_bind_function(L, "find_ceil", smlua_func_find_ceil); <--- UNIMPLEMENTED
|
||||
smlua_bind_function(L, "find_ceil_height", smlua_func_find_ceil_height);
|
||||
|
|
|
@ -305,6 +305,7 @@ u32 smlua_get_action_interaction_type(struct MarioState* m) {
|
|||
|
||||
struct LuaHookedBehavior {
|
||||
u32 behaviorId;
|
||||
u32 overrideId;
|
||||
BehaviorScript behavior[2];
|
||||
int initReference;
|
||||
int loopReference;
|
||||
|
@ -331,7 +332,7 @@ const BehaviorScript* get_lua_behavior_from_id(enum BehaviorId id) {
|
|||
if (L == NULL) { return false; }
|
||||
for (int i = 0; i < sHookedBehaviorsCount; i++) {
|
||||
struct LuaHookedBehavior* hooked = &sHookedBehaviors[i];
|
||||
if (hooked->behaviorId != id) { continue; }
|
||||
if (hooked->behaviorId != id && hooked->overrideId != id) { continue; }
|
||||
return hooked->behavior;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -396,7 +397,8 @@ int smlua_hook_behavior(lua_State* L) {
|
|||
|
||||
struct LuaHookedBehavior* hooked = &sHookedBehaviors[sHookedBehaviorsCount];
|
||||
u16 customBehaviorId = (sHookedBehaviorsCount & 0xFFFF) | LUA_BEHAVIOR_FLAG;
|
||||
hooked->behaviorId = overrideBehaviorId != 0 ? overrideBehaviorId : customBehaviorId;
|
||||
hooked->behaviorId = customBehaviorId;
|
||||
hooked->overrideId = (overrideBehaviorId == 0) ? customBehaviorId : overrideBehaviorId;
|
||||
hooked->behavior[0] = (((unsigned int) (((unsigned int)(0x00) & ((0x01 << (8)) - 1)) << (24))) | ((unsigned int) (((unsigned int)(objectList) & ((0x01 << (8)) - 1)) << (16)))); // gross. this is BEGIN(objectList)
|
||||
hooked->behavior[1] = (((unsigned int) (((unsigned int)(0x39) & ((0x01 << (8)) - 1)) << (24))) | ((unsigned int) (((unsigned int)(customBehaviorId) & ((0x01 << (16)) - 1)) << (0)))); // gross. this is ID(customBehaviorId)
|
||||
hooked->initReference = initReference;
|
||||
|
@ -643,11 +645,13 @@ static void smlua_clear_hooks(void) {
|
|||
sHookedEvents[i].reference[j] = 0;
|
||||
}
|
||||
sHookedEvents[i].count = 0;
|
||||
sHookedEvents[i].entry = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sHookedMarioActionsCount; i++) {
|
||||
sHookedMarioActions[i].action = 0;
|
||||
sHookedMarioActions[i].reference = 0;
|
||||
sHookedMarioActions[i].entry = NULL;
|
||||
}
|
||||
sHookedMarioActionsCount = 0;
|
||||
|
||||
|
@ -659,6 +663,7 @@ static void smlua_clear_hooks(void) {
|
|||
sHookedChatCommands[i].description = NULL;
|
||||
|
||||
sHookedChatCommands[i].reference = 0;
|
||||
sHookedChatCommands[i].entry = NULL;
|
||||
}
|
||||
sHookedChatCommandsCount = 0;
|
||||
|
||||
|
@ -669,6 +674,7 @@ static void smlua_clear_hooks(void) {
|
|||
hooked->behavior[1] = 0;
|
||||
hooked->initReference = 0;
|
||||
hooked->loopReference = 0;
|
||||
hooked->entry = NULL;
|
||||
}
|
||||
sHookedBehaviorsCount = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue