create char/ delete char / get all chars
This commit is contained in:
parent
4bd2f16080
commit
6903d7918a
10 changed files with 749 additions and 15 deletions
|
@ -10,6 +10,12 @@ var _history = Array()
|
|||
const StringManager = preload("res://assets/Scripts/Config/string_manager.gd")
|
||||
var _string_manager = StringManager.new()
|
||||
var _phrases_not_decoded = Array()
|
||||
var _shard_names = Array()
|
||||
var _character_summaries = Array()
|
||||
var _mainlands = Array()
|
||||
|
||||
var _delete_char = false
|
||||
var _launch_create_user = false
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
|
@ -46,7 +52,11 @@ func string_resp(message):
|
|||
var id = msg['string_id'][i]
|
||||
if _string_manager.check_phrases(id) == false:
|
||||
decoded = false
|
||||
var command = {'action': Action.ACTION_GENERIC_CODE, 'impulse': ImpulseBase.STRING_MANAGER_STRING_RQ, "string_id": id}
|
||||
var command = {
|
||||
'action': Action.ACTION_GENERIC_CODE,
|
||||
'impulse': ImpulseBase.STRING_MANAGER_STRING_RQ,
|
||||
"string_id": id
|
||||
}
|
||||
_networkconnection.put_command(command);
|
||||
else:
|
||||
tmp.append(_string_manager.get_phrases(id))
|
||||
|
@ -60,6 +70,195 @@ func string_resp(message):
|
|||
print(template % tmp)
|
||||
_phrases_not_decoded = _phrases_not_decoded_new
|
||||
|
||||
func user_chars(message):
|
||||
_character_summaries = message['character_summaries']
|
||||
_mainlands = message['mainlands']
|
||||
_shard_names = message['shard_names']
|
||||
#for i in message['shard_names']:
|
||||
# _shard_names.append(i)
|
||||
print("---------------")
|
||||
print(_shard_names)
|
||||
print("---------------")
|
||||
print(_mainlands)
|
||||
print("---------------")
|
||||
print(_character_summaries)
|
||||
print("---------------")
|
||||
var listcar = ""
|
||||
for i in range(0, _character_summaries.size()):
|
||||
if _character_summaries[i]['people'] != 142:
|
||||
if listcar.length() > 0:
|
||||
listcar = listcar + ", "
|
||||
listcar = listcar + String(i) + ":" + _character_summaries[i]['name']
|
||||
print(" Perso:" + listcar)
|
||||
append_message_raw(" Perso:" + listcar, "-")
|
||||
print("---------------")
|
||||
|
||||
func append_message(id, flow):
|
||||
# add message to debug
|
||||
var msg = Dictionary()
|
||||
msg['flow'] = flow
|
||||
var impulse_base = ImpulseBase.new()
|
||||
msg['impulse_debug'] = impulse_base.get_name(id)
|
||||
_history.append(msg)
|
||||
|
||||
func append_message_raw(message, flow):
|
||||
# add message to debug
|
||||
var msg = Dictionary()
|
||||
msg['flow'] = flow
|
||||
msg['impulse_debug'] = message
|
||||
_history.append(msg)
|
||||
|
||||
func create_char():
|
||||
var slot = 2
|
||||
if _character_summaries.size() <= slot:
|
||||
return
|
||||
if _character_summaries[slot]['people'] != People.Unknown:
|
||||
if _delete_char == false:
|
||||
print("***** Delete old car")
|
||||
var command = {
|
||||
'action': Action.ACTION_GENERIC_CODE,
|
||||
'impulse': ImpulseBase.CONNECTION_DELETE_CHAR,
|
||||
"slot": slot
|
||||
}
|
||||
_networkconnection.put_command(command);
|
||||
append_message(command['impulse'], '<')
|
||||
_delete_char = true
|
||||
return
|
||||
if _launch_create_user == true:
|
||||
return
|
||||
_launch_create_user = true
|
||||
print("***** Launch command to create User")
|
||||
# Becarefull with check like
|
||||
# nb_point_fighter + nb_point_caster + nb_point_crafter + nb_point_harvester <= 5 # bool CCharacter::checkCreateParams( const CCreateCharMsg& createCharMsg, CCreateCharErrorMsg& createCharErrorMsg, uint32 userId )
|
||||
# hair_color = [0 ... 7] # void setHAIR_COLOR(CCDBSynchronised &dbGroup, uint8 value, bool forceSending = false)
|
||||
# sex = [0 , 1] # bool CCharacter::checkCreateParams( const CCreateCharMsg& createCharMsg, CCreateCharErrorMsg& createCharErrorMsg, uint32 userId )
|
||||
# name :
|
||||
# without spave ! # bool CCharacter::checkCreateParams( const CCreateCharMsg& createCharMsg, CCreateCharErrorMsg& createCharErrorMsg, uint32 userId )
|
||||
# lenght [3 .. 15 ] # CHARSYNC::TCharacterNameResult CNameManager::isNameUsable(const ucstring & ucNameIn, uint32 userId, uint8 charIndex, uint32 homeSessionId)
|
||||
# caratere: Only [A-Z & a-z] # CHARSYNC::TCharacterNameResult CNameManager::isNameUsable(const ucstring & ucNameIn, uint32 userId, uint8 charIndex, uint32 homeSessionId)
|
||||
# I don't undesrantd why we use utf-16 just for just 56 letters !
|
||||
# slot : [0..4] # slot empty # bool CCharacter::checkCreateParams( const CCreateCharMsg& createCharMsg, CCreateCharErrorMsg& createCharErrorMsg, uint32 userId )
|
||||
#
|
||||
# bool CCharacter::checkCreateParams( const CCreateCharMsg& createCharMsg, CCreateCharErrorMsg& createCharErrorMsg, uint32 userId )
|
||||
# void setHAIR_COLOR(CCDBSynchronised &dbGroup, uint8 value, bool forceSending = false)
|
||||
var command1 = {
|
||||
'action': Action.ACTION_GENERIC_CODE,
|
||||
'impulse': ImpulseBase.CONNECTION_CREATE_CHAR,
|
||||
'slot': slot,
|
||||
'sheet_id': 0,
|
||||
'session_id': int(_shard_names[0]['session_id']),
|
||||
'name': "UnSuperTest",
|
||||
'people': People.Zorai,
|
||||
'sex': 1,
|
||||
'nb_point_fighter': 2,
|
||||
'nb_point_caster': 1,
|
||||
'nb_point_crafter': 1,
|
||||
'nb_point_harvester': 1,
|
||||
'start_point': 2281701451,
|
||||
'hair_type': 7,
|
||||
'hair_color': 7,
|
||||
'gabarit_height': 255,
|
||||
'gabarit_torso_width': 255,
|
||||
'gabarit_arms_width': 255,
|
||||
'gabarit_legs_width': 255,
|
||||
'gabarit_breast_size': 255,
|
||||
'morph_target_1': 255,
|
||||
'morph_target_2': 255,
|
||||
'morph_target_3': 255,
|
||||
'morph_target_4': 255,
|
||||
'morph_target_5': 255,
|
||||
'morph_target_6': 255,
|
||||
'morph_target_7': 255,
|
||||
'morph_target_8': 255,
|
||||
'eyes_color': 255,
|
||||
'tattoo': 255,
|
||||
'jacket_color': 255,
|
||||
'trousers_color': 255,
|
||||
'hat_color': 255,
|
||||
'arms_color': 255,
|
||||
'hands_color': 255,
|
||||
'feet_color': 255
|
||||
}
|
||||
var command2 = {
|
||||
'action': Action.ACTION_GENERIC_CODE,
|
||||
'impulse': ImpulseBase.CONNECTION_CREATE_CHAR,
|
||||
'slot': slot,
|
||||
'sheet_id': 0,
|
||||
'session_id': int(_shard_names[0]['session_id']),
|
||||
'name': "UnSuperTest",
|
||||
'people': People.Fyros,
|
||||
'sex': 1,
|
||||
'nb_point_fighter': 2,
|
||||
'nb_point_caster': 1,
|
||||
'nb_point_crafter': 1,
|
||||
'nb_point_harvester': 1,
|
||||
'start_point': 123,
|
||||
'hair_type': 1,
|
||||
'hair_color': 2,
|
||||
'gabarit_height': 3,
|
||||
'gabarit_torso_width': 4,
|
||||
'gabarit_arms_width': 5,
|
||||
'gabarit_legs_width': 6,
|
||||
'gabarit_breast_size': 7,
|
||||
'morph_target_1': 8,
|
||||
'morph_target_2': 9,
|
||||
'morph_target_3': 10,
|
||||
'morph_target_4': 11,
|
||||
'morph_target_5': 12,
|
||||
'morph_target_6': 13,
|
||||
'morph_target_7': 14,
|
||||
'morph_target_8': 15,
|
||||
'eyes_color': 16,
|
||||
'tattoo': 17,
|
||||
'jacket_color': 18,
|
||||
'trousers_color': 19,
|
||||
'hat_color': 20,
|
||||
'arms_color': 21,
|
||||
'hands_color': 22,
|
||||
'feet_color': 23
|
||||
}
|
||||
var command = {
|
||||
'action': Action.ACTION_GENERIC_CODE,
|
||||
'impulse': ImpulseBase.CONNECTION_CREATE_CHAR,
|
||||
'slot': slot,
|
||||
'sheet_id': 0,
|
||||
'session_id': int(_shard_names[0]['session_id']),
|
||||
'name': "UnSuperTest",
|
||||
'people': People.Fyros,
|
||||
'sex': 1,
|
||||
'nb_point_fighter': 0,
|
||||
'nb_point_caster': 0,
|
||||
'nb_point_crafter': 0,
|
||||
'nb_point_harvester': 0,
|
||||
'start_point': 0,
|
||||
'hair_type': 0,
|
||||
'hair_color': 0,
|
||||
'gabarit_height': 0,
|
||||
'gabarit_torso_width': 0,
|
||||
'gabarit_arms_width': 0,
|
||||
'gabarit_legs_width': 0,
|
||||
'gabarit_breast_size': 0,
|
||||
'morph_target_1': 0,
|
||||
'morph_target_2': 0,
|
||||
'morph_target_3': 0,
|
||||
'morph_target_4': 0,
|
||||
'morph_target_5': 0,
|
||||
'morph_target_6': 0,
|
||||
'morph_target_7': 0,
|
||||
'morph_target_8': 0,
|
||||
'eyes_color': 0,
|
||||
'tattoo': 0,
|
||||
'jacket_color': 0,
|
||||
'trousers_color': 0,
|
||||
'hat_color': 0,
|
||||
'arms_color': 0,
|
||||
'hands_color': 0,
|
||||
'feet_color': 0
|
||||
}
|
||||
_networkconnection.put_command(command);
|
||||
append_message(command['impulse'], '<')
|
||||
_delete_char = true
|
||||
|
||||
func analyze_message(message):
|
||||
if message['action'] == Action.ACTION_POSITION_CODE:
|
||||
pass
|
||||
|
@ -72,7 +271,9 @@ func analyze_message(message):
|
|||
elif message['impulse'] == ImpulseBase.STRING_MANAGER_STRING_RESP:
|
||||
string_resp(message)
|
||||
elif message['impulse'] == ImpulseBase.CONNECTION_USER_CHARS:
|
||||
pass
|
||||
user_chars(message)
|
||||
# Normally this step is executed when player ask to create
|
||||
create_char()
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(delta):
|
||||
|
@ -82,16 +283,17 @@ func _process(delta):
|
|||
while data.size() >0:
|
||||
var message = data.pop_front()
|
||||
_history.append(message)
|
||||
message['flow'] = '>'
|
||||
print(message)
|
||||
analyze_message(message)
|
||||
if _history.size() > 0:
|
||||
# just to see last message (normally cleanned each time we read message)
|
||||
while _history.size() > 10:
|
||||
while _history.size() > 20:
|
||||
var element = _history.pop_front()
|
||||
print("*** remove:" , element)
|
||||
var message = "tick :" + String(_networkconnection.get_server_tick()) + '\n'
|
||||
for i in range(0, _history.size()):
|
||||
message += String(_history[i]) + '\n'
|
||||
message += "Server " + _history[i]['flow'] + " Client : " + String(_history[i]['impulse_debug']) + '\n'
|
||||
$label.text = message
|
||||
|
||||
func _show():
|
||||
|
|
|
@ -32,6 +32,75 @@
|
|||
#include "action_genericmultipart.h"
|
||||
#include "action.h"
|
||||
|
||||
struct SPropVisualA
|
||||
{
|
||||
struct SPropSubData // 64 bits used
|
||||
{
|
||||
uint64_t Sex : 1; // max: 2 current: 2
|
||||
uint64_t JacketModel : 8; // max: 256 current: 93
|
||||
uint64_t JacketColor : 3; // max: 8 current: 8
|
||||
uint64_t TrouserModel : 8; // max: 256 current: 104
|
||||
uint64_t TrouserColor : 3; // max: 8 current: 8
|
||||
uint64_t WeaponRightHand : 10; // max: 1024 current: 457
|
||||
uint64_t WeaponLeftHand : 8; // max: 256 current: 63
|
||||
uint64_t ArmModel : 8; // max: 256 current: 94
|
||||
uint64_t ArmColor : 3; // max: 8 current: 8
|
||||
uint64_t HatModel : 9; // max: 512 current: 192
|
||||
uint64_t HatColor : 3; // max: 8 current: 8
|
||||
};
|
||||
union
|
||||
{
|
||||
uint64_t PropertyA;
|
||||
SPropSubData PropertySubData;
|
||||
};
|
||||
};
|
||||
|
||||
struct SPropVisualB
|
||||
{
|
||||
struct SPropSubData // 47 bits used
|
||||
{
|
||||
uint64_t Name : 16;
|
||||
uint64_t HandsModel : 9; // max: 512 current: 90
|
||||
uint64_t HandsColor : 3; // max: 8 current: 8
|
||||
uint64_t FeetModel : 9; // max: 512 current: 94
|
||||
uint64_t FeetColor : 3; // max: 8 current: 8
|
||||
uint64_t RTrail : 4;
|
||||
uint64_t LTrail : 3;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint64_t PropertyB;
|
||||
SPropSubData PropertySubData;
|
||||
};
|
||||
};
|
||||
|
||||
struct SPropVisualC
|
||||
{
|
||||
struct SPropSubData // 54 bits used
|
||||
{
|
||||
uint64_t MorphTarget1 : 3; // max: 8 current: 8
|
||||
uint64_t MorphTarget2 : 3; // max: 8 current: 8
|
||||
uint64_t MorphTarget3 : 3; // max: 8 current: 8
|
||||
uint64_t MorphTarget4 : 3; // max: 8 current: 8
|
||||
uint64_t MorphTarget5 : 3; // max: 8 current: 8
|
||||
uint64_t MorphTarget6 : 3; // max: 8 current: 8
|
||||
uint64_t MorphTarget7 : 3; // max: 8 current: 8
|
||||
uint64_t MorphTarget8 : 3; // max: 8 current: 8
|
||||
uint64_t EyesColor : 3; // max: 8 current: 8
|
||||
uint64_t Tattoo : 7; // max: 128 current: 64
|
||||
uint64_t CharacterHeight : 4; // max: 16 current: 16
|
||||
uint64_t TorsoWidth : 4; // max: 16 current: 16
|
||||
uint64_t ArmsWidth : 4; // max: 16 current: 16
|
||||
uint64_t LegsWidth : 4; // max: 16 current: 16
|
||||
uint64_t BreastSize : 4; // max: 16 current: 16
|
||||
};
|
||||
union
|
||||
{
|
||||
uint64_t PropertyC;
|
||||
SPropSubData PropertySubData;
|
||||
};
|
||||
};
|
||||
|
||||
void ActionFactory::decode_message(NetworkData * data, Ref<BitStream> msgin)
|
||||
{
|
||||
Dictionary value;
|
||||
|
@ -84,20 +153,65 @@ void ActionFactory::decode_message(NetworkData * data, Ref<BitStream> msgin)
|
|||
for(i=0;i<character_summaries_Len;++i)
|
||||
{
|
||||
Dictionary character;
|
||||
SPropVisualA visual_prop_a;
|
||||
SPropVisualB visual_prop_b;
|
||||
SPropVisualC visual_prop_c;
|
||||
character["version"] = msgin->get_version();
|
||||
character["mainland"] = msgin->get_uint32();
|
||||
character["name"] = msgin->get_string_utf16(); // msgin->get_ustring();
|
||||
character["name"] = msgin->get_string_utf16();
|
||||
character["people"] = msgin->get_uint32();
|
||||
character["location"] = msgin->get_uint32();
|
||||
character["visual_prop_a"] = msgin->get_uint64();
|
||||
character["visual_prop_b"] = msgin->get_uint64();
|
||||
character["visual_prop_c"] = msgin->get_uint64();
|
||||
// khanat-opennel-code/code/ryzom/common/src/game_share/player_visual_properties.h # struct SPropVisualA
|
||||
visual_prop_a.PropertyA = msgin->get_uint64();
|
||||
visual_prop_b.PropertyB = msgin->get_uint64();
|
||||
visual_prop_c.PropertyC = msgin->get_uint64();
|
||||
character["sheet_id"] = msgin->get_uint32();
|
||||
character["title"] = msgin->get_sint32();
|
||||
character["character_slot"] = msgin->get_uint8();
|
||||
character["in_ring_session"] = msgin->get_bool();
|
||||
character["has_edit_session"] = msgin->get_bool();
|
||||
character["in_newbieland"] = msgin->get_bool();
|
||||
|
||||
character["visual_prop_a"] = visual_prop_a.PropertyA;
|
||||
character["visual_prop_b"] = visual_prop_b.PropertyB;
|
||||
character["visual_prop_c"] = visual_prop_c.PropertyC;
|
||||
|
||||
character["sex"] = visual_prop_a.PropertySubData.Sex;
|
||||
character["jacket_model"] = visual_prop_a.PropertySubData.JacketModel;
|
||||
character["jacket_color"] = visual_prop_a.PropertySubData.JacketColor;
|
||||
character["trouser_model"] = visual_prop_a.PropertySubData.TrouserModel;
|
||||
character["trouser_color"] = visual_prop_a.PropertySubData.TrouserColor;
|
||||
character["weapon_right_hand"] = visual_prop_a.PropertySubData.WeaponRightHand;
|
||||
character["weapon_left_hand"] = visual_prop_a.PropertySubData.WeaponLeftHand;
|
||||
character["arm_model"] = visual_prop_a.PropertySubData.ArmModel;
|
||||
character["arm_color"] = visual_prop_a.PropertySubData.ArmColor;
|
||||
character["hat_model"] = visual_prop_a.PropertySubData.HatModel;
|
||||
character["hat_color"] = visual_prop_a.PropertySubData.HatColor;
|
||||
|
||||
character["name_extra"] = visual_prop_b.PropertySubData.Name;
|
||||
character["hands_model"] = visual_prop_b.PropertySubData.HandsModel;
|
||||
character["hands_color"] = visual_prop_b.PropertySubData.HandsColor;
|
||||
character["feet_model"] = visual_prop_b.PropertySubData.FeetModel;
|
||||
character["feet_color"] = visual_prop_b.PropertySubData.FeetColor;
|
||||
character["right_trail"] = visual_prop_b.PropertySubData.RTrail;
|
||||
character["left_trail"] = visual_prop_b.PropertySubData.LTrail;
|
||||
|
||||
character["morph_target_1"] = visual_prop_c.PropertySubData.MorphTarget1;
|
||||
character["morph_target_2"] = visual_prop_c.PropertySubData.MorphTarget2;
|
||||
character["morph_target_3"] = visual_prop_c.PropertySubData.MorphTarget3;
|
||||
character["morph_target_4"] = visual_prop_c.PropertySubData.MorphTarget4;
|
||||
character["morph_target_5"] = visual_prop_c.PropertySubData.MorphTarget5;
|
||||
character["morph_target_6"] = visual_prop_c.PropertySubData.MorphTarget6;
|
||||
character["morph_target_7"] = visual_prop_c.PropertySubData.MorphTarget7;
|
||||
character["morph_target_8"] = visual_prop_c.PropertySubData.MorphTarget8;
|
||||
character["eyes_color"] = visual_prop_c.PropertySubData.EyesColor;
|
||||
character["tattoo"] = visual_prop_c.PropertySubData.Tattoo;
|
||||
character["character_height"] = visual_prop_c.PropertySubData.CharacterHeight;
|
||||
character["torso_width"] = visual_prop_c.PropertySubData.TorsoWidth;
|
||||
character["arms_width"] = visual_prop_c.PropertySubData.ArmsWidth;
|
||||
character["legs_width"] = visual_prop_c.PropertySubData.LegsWidth;
|
||||
character["breast_size"] = visual_prop_c.PropertySubData.BreastSize;
|
||||
|
||||
character_summaries.append(character);
|
||||
}
|
||||
value["character_summaries"] = character_summaries;
|
||||
|
@ -108,7 +222,9 @@ void ActionFactory::decode_message(NetworkData * data, Ref<BitStream> msgin)
|
|||
for(i=0;i<shard_names_Len;++i)
|
||||
{
|
||||
Dictionary shard_name;
|
||||
shard_name["shard_names"] = msgin->get_string();
|
||||
shard_name["session_id"] = msgin->get_string(); ++i;
|
||||
shard_name["display_name"] = msgin->get_string(); ++i;
|
||||
shard_name["short_name"] = msgin->get_string(); ++i;
|
||||
shard_names.append(shard_name);
|
||||
}
|
||||
value["shard_names"] = shard_names;
|
||||
|
@ -1512,8 +1628,15 @@ void ActionFactory::encode_message(Dictionary value, Ref<BitStream> msgout)
|
|||
DBG_PRINT("[ActionFactory::pack] ACTION_GENERIC_CODE encode_message B:" + itos(id) + " / " + msgout->show_detail());
|
||||
break;
|
||||
}
|
||||
case ImpulseBase::Impulse::CONNECTION_DELETE_CHAR:
|
||||
{
|
||||
uint8_t slot = value["slot"];
|
||||
msgout->put_uint8(slot);
|
||||
break;
|
||||
}
|
||||
case ImpulseBase::Impulse::CONNECTION_CREATE_CHAR:
|
||||
{
|
||||
// khanat-opennel-code/code/ryzom/server/src/entities_game_service/player_manager/character.cpp:7977 bool CCharacter::checkCreateParams( const CCreateCharMsg& createCharMsg, CCreateCharErrorMsg& createCharErrorMsg, uint32 userId )
|
||||
uint8_t slot = value["slot"];
|
||||
uint8_t people = value["people"];
|
||||
uint8_t sex = value["sex"];
|
||||
|
@ -1558,7 +1681,7 @@ void ActionFactory::encode_message(Dictionary value, Ref<BitStream> msgout)
|
|||
msgout->put_uint8(nb_point_caster);
|
||||
msgout->put_uint8(nb_point_crafter);
|
||||
msgout->put_uint8(nb_point_harvester);
|
||||
msgout->put_uint8(start_point);
|
||||
msgout->put_uint32(start_point);
|
||||
msgout->put_uint8(hair_type);
|
||||
msgout->put_uint8(hair_color);
|
||||
msgout->put_uint8(gabarit_height);
|
||||
|
|
|
@ -78,6 +78,7 @@ void BitStream::_bind_methods()
|
|||
ClassDB::bind_method(D_METHOD("get_string"), &BitStream::get_string);
|
||||
ClassDB::bind_method(D_METHOD("get_string_utf16"), &BitStream::get_string_utf16);
|
||||
ClassDB::bind_method(D_METHOD("get_string_utf8"), &BitStream::get_string_utf8);
|
||||
|
||||
}
|
||||
|
||||
void BitStream::clear()
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "core/array.h"
|
||||
#include "core/variant.h"
|
||||
#include "core/int_types.h"
|
||||
#include "modules/debug/debug.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Macros extracted from icu/unicode/utf16.h
|
||||
|
@ -305,10 +306,13 @@ void convert_utf8_to_utf16(String input, uint16_t ** u16_buf, size_t * u16_len)
|
|||
}
|
||||
|
||||
*u16_buf = new uint16_t[*u16_len];
|
||||
size_t ii;
|
||||
(*u16_len)--;
|
||||
size_t ii = 0;
|
||||
DBG_PRINT("array (max:" + itos(*u16_len));
|
||||
for (i = 0; i < unicode.size(); ++i)
|
||||
{
|
||||
unsigned long uni = unicode[i];
|
||||
DBG_PRINT("array (max:" + itos(*u16_len) + " / i:" + itos(i) + " / current:" + itos(ii) + ")");
|
||||
if (uni <= 0xFFFF)
|
||||
{
|
||||
(*u16_buf)[ii++] = uni;
|
||||
|
@ -320,8 +324,9 @@ void convert_utf8_to_utf16(String input, uint16_t ** u16_buf, size_t * u16_len)
|
|||
(*u16_buf)[ii++] = (uint16_t)((uni & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
ii--;
|
||||
#ifdef DEBUG_ENABLED
|
||||
if(ii > *u16_len)
|
||||
if(ii != *u16_len)
|
||||
{
|
||||
ERR_PRINT("Out of array (max:" + itos(*u16_len) + " / current:" + itos(ii) + ")");
|
||||
throw "Out of array";
|
||||
|
|
|
@ -358,6 +358,8 @@ void ImpulseBase::_bind_methods()
|
|||
BIND_ENUM_CONSTANT(NPC_ICON_SVR_EVENT_MIS_AVL);
|
||||
BIND_ENUM_CONSTANT(NPC_ICON_SET_TIMER);
|
||||
BIND_ENUM_CONSTANT(__LAST_ELEMENT);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_name", "id"), &ImpulseBase::get_name);
|
||||
}
|
||||
|
||||
int ImpulseBase::get_command(String name)
|
||||
|
@ -1713,4 +1715,10 @@ String ImpulseBase::get_command_name(uint32_t id)
|
|||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
String ImpulseBase::get_name(Variant id)
|
||||
{
|
||||
uint32_t _id = id;
|
||||
return ImpulseBase::get_command_name(_id);
|
||||
}
|
|
@ -374,6 +374,7 @@ public:
|
|||
|
||||
static int get_command(String name);
|
||||
static String get_command_name(uint32_t id);
|
||||
String get_name(Variant id);
|
||||
};
|
||||
|
||||
|
||||
|
|
188
modules/impulse/people.cpp
Normal file
188
modules/impulse/people.cpp
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
People Library
|
||||
|
||||
Copyright (C) 2019 AleaJactaEst
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include "people.h"
|
||||
|
||||
void People::_bind_methods()
|
||||
{
|
||||
BIND_ENUM_CONSTANT(Undefined);
|
||||
BIND_ENUM_CONSTANT(Humanoid);
|
||||
BIND_ENUM_CONSTANT(Playable);
|
||||
BIND_ENUM_CONSTANT(Fyros);
|
||||
BIND_ENUM_CONSTANT(Matis);
|
||||
BIND_ENUM_CONSTANT(Tryker);
|
||||
BIND_ENUM_CONSTANT(Zorai);
|
||||
BIND_ENUM_CONSTANT(EndPlayable);
|
||||
BIND_ENUM_CONSTANT(Karavan);
|
||||
BIND_ENUM_CONSTANT(Tribe);
|
||||
BIND_ENUM_CONSTANT(Common);
|
||||
BIND_ENUM_CONSTANT(EndHumanoid);
|
||||
BIND_ENUM_CONSTANT(Creature);
|
||||
BIND_ENUM_CONSTANT(Fauna);
|
||||
BIND_ENUM_CONSTANT(Arma);
|
||||
BIND_ENUM_CONSTANT(Balduse);
|
||||
BIND_ENUM_CONSTANT(Bul);
|
||||
BIND_ENUM_CONSTANT(Capryni);
|
||||
BIND_ENUM_CONSTANT(Chonari);
|
||||
BIND_ENUM_CONSTANT(Clapclap);
|
||||
BIND_ENUM_CONSTANT(Cococlaw);
|
||||
BIND_ENUM_CONSTANT(Cute);
|
||||
BIND_ENUM_CONSTANT(Dag);
|
||||
BIND_ENUM_CONSTANT(Diranak);
|
||||
BIND_ENUM_CONSTANT(Estrasson);
|
||||
BIND_ENUM_CONSTANT(Filin);
|
||||
BIND_ENUM_CONSTANT(Frahar);
|
||||
BIND_ENUM_CONSTANT(Gibbai);
|
||||
BIND_ENUM_CONSTANT(Hachtaha);
|
||||
BIND_ENUM_CONSTANT(Jungler);
|
||||
BIND_ENUM_CONSTANT(Kakty);
|
||||
BIND_ENUM_CONSTANT(Kalab);
|
||||
BIND_ENUM_CONSTANT(Kami);
|
||||
BIND_ENUM_CONSTANT(Kazoar);
|
||||
BIND_ENUM_CONSTANT(Kitin);
|
||||
BIND_ENUM_CONSTANT(Kitins);
|
||||
BIND_ENUM_CONSTANT(Kitifly);
|
||||
BIND_ENUM_CONSTANT(Kitihank);
|
||||
BIND_ENUM_CONSTANT(Kitiharak);
|
||||
BIND_ENUM_CONSTANT(Kitikil);
|
||||
BIND_ENUM_CONSTANT(Kitimandib);
|
||||
BIND_ENUM_CONSTANT(Kitinagan);
|
||||
BIND_ENUM_CONSTANT(Kitinega);
|
||||
BIND_ENUM_CONSTANT(Kitinokto);
|
||||
BIND_ENUM_CONSTANT(EndKitins);
|
||||
BIND_ENUM_CONSTANT(Lightbird);
|
||||
BIND_ENUM_CONSTANT(Mektoub);
|
||||
BIND_ENUM_CONSTANT(MektoubPacker);
|
||||
BIND_ENUM_CONSTANT(MektoubMount);
|
||||
BIND_ENUM_CONSTANT(Pucetron);
|
||||
BIND_ENUM_CONSTANT(Regus);
|
||||
BIND_ENUM_CONSTANT(Ryzerb);
|
||||
BIND_ENUM_CONSTANT(Ryzoholo);
|
||||
BIND_ENUM_CONSTANT(Ryzoholok);
|
||||
BIND_ENUM_CONSTANT(Vampignon);
|
||||
BIND_ENUM_CONSTANT(Varinx);
|
||||
BIND_ENUM_CONSTANT(Yber);
|
||||
BIND_ENUM_CONSTANT(Zerx);
|
||||
BIND_ENUM_CONSTANT(race_c1);
|
||||
BIND_ENUM_CONSTANT(race_c2);
|
||||
BIND_ENUM_CONSTANT(race_c3);
|
||||
BIND_ENUM_CONSTANT(race_c4);
|
||||
BIND_ENUM_CONSTANT(race_c5);
|
||||
BIND_ENUM_CONSTANT(race_c6);
|
||||
BIND_ENUM_CONSTANT(race_c7);
|
||||
BIND_ENUM_CONSTANT(race_h1);
|
||||
BIND_ENUM_CONSTANT(race_h2);
|
||||
BIND_ENUM_CONSTANT(race_h3);
|
||||
BIND_ENUM_CONSTANT(race_h4);
|
||||
BIND_ENUM_CONSTANT(race_h5);
|
||||
BIND_ENUM_CONSTANT(race_h6);
|
||||
BIND_ENUM_CONSTANT(race_h7);
|
||||
BIND_ENUM_CONSTANT(race_h8);
|
||||
BIND_ENUM_CONSTANT(race_h9);
|
||||
BIND_ENUM_CONSTANT(race_h10);
|
||||
BIND_ENUM_CONSTANT(race_h11);
|
||||
BIND_ENUM_CONSTANT(race_h12);
|
||||
BIND_ENUM_CONSTANT(EndFauna);
|
||||
BIND_ENUM_CONSTANT(Flora);
|
||||
BIND_ENUM_CONSTANT(Cephaloplant);
|
||||
BIND_ENUM_CONSTANT(Electroalgs);
|
||||
BIND_ENUM_CONSTANT(Phytopsy);
|
||||
BIND_ENUM_CONSTANT(SapEnslaver);
|
||||
BIND_ENUM_CONSTANT(SpittingWeeds);
|
||||
BIND_ENUM_CONSTANT(Swarmplants);
|
||||
BIND_ENUM_CONSTANT(EndFlora);
|
||||
BIND_ENUM_CONSTANT(Goo);
|
||||
BIND_ENUM_CONSTANT(GooFauna);
|
||||
BIND_ENUM_CONSTANT(GooArma);
|
||||
BIND_ENUM_CONSTANT(GooBalduse);
|
||||
BIND_ENUM_CONSTANT(GooBul);
|
||||
BIND_ENUM_CONSTANT(GooCapryni);
|
||||
BIND_ENUM_CONSTANT(GooChonari);
|
||||
BIND_ENUM_CONSTANT(GooClapclap);
|
||||
BIND_ENUM_CONSTANT(GooCococlaw);
|
||||
BIND_ENUM_CONSTANT(GooCute);
|
||||
BIND_ENUM_CONSTANT(GooDag);
|
||||
BIND_ENUM_CONSTANT(GooDiranak);
|
||||
BIND_ENUM_CONSTANT(GooEstrasson);
|
||||
BIND_ENUM_CONSTANT(GooFilin);
|
||||
BIND_ENUM_CONSTANT(GooFrahar);
|
||||
BIND_ENUM_CONSTANT(GooGibbai);
|
||||
BIND_ENUM_CONSTANT(GooHachtaha);
|
||||
BIND_ENUM_CONSTANT(GooJungler);
|
||||
BIND_ENUM_CONSTANT(GooKakty);
|
||||
BIND_ENUM_CONSTANT(GooKalab);
|
||||
BIND_ENUM_CONSTANT(GooKami);
|
||||
BIND_ENUM_CONSTANT(GooKazoar);
|
||||
BIND_ENUM_CONSTANT(GooKitifly);
|
||||
BIND_ENUM_CONSTANT(GooKitihank);
|
||||
BIND_ENUM_CONSTANT(GooKitiharak);
|
||||
BIND_ENUM_CONSTANT(GooKitikil);
|
||||
BIND_ENUM_CONSTANT(GooKitimandib);
|
||||
BIND_ENUM_CONSTANT(GooKitin);
|
||||
BIND_ENUM_CONSTANT(GooKitinagan);
|
||||
BIND_ENUM_CONSTANT(GooKitinega);
|
||||
BIND_ENUM_CONSTANT(GooKitinokto);
|
||||
BIND_ENUM_CONSTANT(GooLightbird);
|
||||
BIND_ENUM_CONSTANT(GooMektoub);
|
||||
BIND_ENUM_CONSTANT(GooMektoubPacker);
|
||||
BIND_ENUM_CONSTANT(GooMektoubMount);
|
||||
BIND_ENUM_CONSTANT(GooPucetron);
|
||||
BIND_ENUM_CONSTANT(GooRegus);
|
||||
BIND_ENUM_CONSTANT(GooRyzerb);
|
||||
BIND_ENUM_CONSTANT(GooRyzoholo);
|
||||
BIND_ENUM_CONSTANT(GooRyzoholok);
|
||||
BIND_ENUM_CONSTANT(GooVampignon);
|
||||
BIND_ENUM_CONSTANT(GooVarinx);
|
||||
BIND_ENUM_CONSTANT(GooYber);
|
||||
BIND_ENUM_CONSTANT(GooZerx);
|
||||
BIND_ENUM_CONSTANT(Goorace_c1);
|
||||
BIND_ENUM_CONSTANT(Goorace_c2);
|
||||
BIND_ENUM_CONSTANT(Goorace_c3);
|
||||
BIND_ENUM_CONSTANT(Goorace_c4);
|
||||
BIND_ENUM_CONSTANT(Goorace_c5);
|
||||
BIND_ENUM_CONSTANT(Goorace_c6);
|
||||
BIND_ENUM_CONSTANT(Goorace_c7);
|
||||
BIND_ENUM_CONSTANT(Goorace_h1);
|
||||
BIND_ENUM_CONSTANT(Goorace_h2);
|
||||
BIND_ENUM_CONSTANT(Goorace_h3);
|
||||
BIND_ENUM_CONSTANT(Goorace_h4);
|
||||
BIND_ENUM_CONSTANT(Goorace_h5);
|
||||
BIND_ENUM_CONSTANT(Goorace_h6);
|
||||
BIND_ENUM_CONSTANT(Goorace_h7);
|
||||
BIND_ENUM_CONSTANT(Goorace_h8);
|
||||
BIND_ENUM_CONSTANT(Goorace_h9);
|
||||
BIND_ENUM_CONSTANT(Goorace_h10);
|
||||
BIND_ENUM_CONSTANT(Goorace_h11);
|
||||
BIND_ENUM_CONSTANT(Goorace_h12);
|
||||
BIND_ENUM_CONSTANT(EndGooFauna);
|
||||
BIND_ENUM_CONSTANT(GooPlant);
|
||||
BIND_ENUM_CONSTANT(GooCephaloplant);
|
||||
BIND_ENUM_CONSTANT(GooElectroalgs);
|
||||
BIND_ENUM_CONSTANT(GooPhytopsy);
|
||||
BIND_ENUM_CONSTANT(GooSapEnslaver);
|
||||
BIND_ENUM_CONSTANT(GooSpittingWeeds);
|
||||
BIND_ENUM_CONSTANT(GooSwarmplants);
|
||||
BIND_ENUM_CONSTANT(EndGooPlant);
|
||||
BIND_ENUM_CONSTANT(EndGoo);
|
||||
BIND_ENUM_CONSTANT(EndCreature);
|
||||
BIND_ENUM_CONSTANT(___TPeople_useSize);
|
||||
BIND_ENUM_CONSTANT(Unknown);
|
||||
BIND_ENUM_CONSTANT(EndPeople);
|
||||
}
|
203
modules/impulse/people.h
Normal file
203
modules/impulse/people.h
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
Header Impulse
|
||||
|
||||
Copyright (C) 2019 AleaJactaEst
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PEOPLE_BASE_H
|
||||
#define PEOPLE_BASE_H
|
||||
|
||||
#include "core/object.h"
|
||||
#include "core/reference.h"
|
||||
|
||||
class People : public Reference
|
||||
{
|
||||
GDCLASS(People, Reference)
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
enum ePeople {
|
||||
Undefined = -1,
|
||||
Humanoid = 0,
|
||||
Playable = 0,
|
||||
Fyros = 0,
|
||||
Matis = 1,
|
||||
Tryker = 2,
|
||||
Zorai = 3,
|
||||
EndPlayable = 4,
|
||||
Karavan = 4,
|
||||
Tribe = 5,
|
||||
Common = 6,
|
||||
EndHumanoid = 7,
|
||||
Creature = 7,
|
||||
Fauna = 7,
|
||||
Arma = 7,
|
||||
Balduse = 8,
|
||||
Bul = 9,
|
||||
Capryni = 10,
|
||||
Chonari = 11,
|
||||
Clapclap = 12,
|
||||
Cococlaw = 13,
|
||||
Cute = 14,
|
||||
Dag = 15,
|
||||
Diranak = 16,
|
||||
Estrasson = 17,
|
||||
Filin = 18,
|
||||
Frahar = 19,
|
||||
Gibbai = 20,
|
||||
Hachtaha = 21,
|
||||
Jungler = 22,
|
||||
Kakty = 23,
|
||||
Kalab = 24,
|
||||
Kami = 25,
|
||||
Kazoar = 26,
|
||||
Kitin = 27,
|
||||
Kitins = 28,
|
||||
Kitifly = 28,
|
||||
Kitihank = 29,
|
||||
Kitiharak = 30,
|
||||
Kitikil = 31,
|
||||
Kitimandib = 32,
|
||||
Kitinagan = 33,
|
||||
Kitinega = 34,
|
||||
Kitinokto = 35,
|
||||
EndKitins = 36,
|
||||
Lightbird = 36,
|
||||
Mektoub = 37,
|
||||
MektoubPacker = 38,
|
||||
MektoubMount = 39,
|
||||
Pucetron = 40,
|
||||
Regus = 41,
|
||||
Ryzerb = 42,
|
||||
Ryzoholo = 43,
|
||||
Ryzoholok = 44,
|
||||
Vampignon = 45,
|
||||
Varinx = 46,
|
||||
Yber = 47,
|
||||
Zerx = 48,
|
||||
race_c1 = 49,
|
||||
race_c2 = 50,
|
||||
race_c3 = 51,
|
||||
race_c4 = 52,
|
||||
race_c5 = 53,
|
||||
race_c6 = 54,
|
||||
race_c7 = 55,
|
||||
race_h1 = 56,
|
||||
race_h2 = 57,
|
||||
race_h3 = 58,
|
||||
race_h4 = 59,
|
||||
race_h5 = 60,
|
||||
race_h6 = 61,
|
||||
race_h7 = 62,
|
||||
race_h8 = 63,
|
||||
race_h9 = 64,
|
||||
race_h10 = 65,
|
||||
race_h11 = 66,
|
||||
race_h12 = 67,
|
||||
EndFauna = 68,
|
||||
Flora = 68,
|
||||
Cephaloplant = 68,
|
||||
Electroalgs = 69,
|
||||
Phytopsy = 70,
|
||||
SapEnslaver = 71,
|
||||
SpittingWeeds = 72,
|
||||
Swarmplants = 73,
|
||||
EndFlora = 74,
|
||||
Goo = 74,
|
||||
GooFauna = 74,
|
||||
GooArma = 74,
|
||||
GooBalduse = 75,
|
||||
GooBul = 76,
|
||||
GooCapryni = 77,
|
||||
GooChonari = 78,
|
||||
GooClapclap = 79,
|
||||
GooCococlaw = 80,
|
||||
GooCute = 81,
|
||||
GooDag = 82,
|
||||
GooDiranak = 83,
|
||||
GooEstrasson = 84,
|
||||
GooFilin = 85,
|
||||
GooFrahar = 86,
|
||||
GooGibbai = 87,
|
||||
GooHachtaha = 88,
|
||||
GooJungler = 89,
|
||||
GooKakty = 90,
|
||||
GooKalab = 91,
|
||||
GooKami = 92,
|
||||
GooKazoar = 93,
|
||||
GooKitifly = 94,
|
||||
GooKitihank = 95,
|
||||
GooKitiharak = 96,
|
||||
GooKitikil = 97,
|
||||
GooKitimandib = 98,
|
||||
GooKitin = 99,
|
||||
GooKitinagan = 100,
|
||||
GooKitinega = 101,
|
||||
GooKitinokto = 102,
|
||||
GooLightbird = 103,
|
||||
GooMektoub = 104,
|
||||
GooMektoubPacker = 105,
|
||||
GooMektoubMount = 106,
|
||||
GooPucetron = 107,
|
||||
GooRegus = 108,
|
||||
GooRyzerb = 109,
|
||||
GooRyzoholo = 110,
|
||||
GooRyzoholok = 111,
|
||||
GooVampignon = 112,
|
||||
GooVarinx = 113,
|
||||
GooYber = 114,
|
||||
GooZerx = 115,
|
||||
Goorace_c1 = 116,
|
||||
Goorace_c2 = 117,
|
||||
Goorace_c3 = 118,
|
||||
Goorace_c4 = 119,
|
||||
Goorace_c5 = 120,
|
||||
Goorace_c6 = 121,
|
||||
Goorace_c7 = 122,
|
||||
Goorace_h1 = 123,
|
||||
Goorace_h2 = 124,
|
||||
Goorace_h3 = 125,
|
||||
Goorace_h4 = 126,
|
||||
Goorace_h5 = 127,
|
||||
Goorace_h6 = 128,
|
||||
Goorace_h7 = 129,
|
||||
Goorace_h8 = 130,
|
||||
Goorace_h9 = 131,
|
||||
Goorace_h10 = 132,
|
||||
Goorace_h11 = 133,
|
||||
Goorace_h12 = 134,
|
||||
EndGooFauna = 135,
|
||||
GooPlant = 135,
|
||||
GooCephaloplant = 135,
|
||||
GooElectroalgs = 136,
|
||||
GooPhytopsy = 137,
|
||||
GooSapEnslaver = 138,
|
||||
GooSpittingWeeds = 139,
|
||||
GooSwarmplants = 140,
|
||||
EndGooPlant = 141,
|
||||
EndGoo = 141,
|
||||
EndCreature = 141,
|
||||
___TPeople_useSize = 142,
|
||||
Unknown = 142,
|
||||
EndPeople = 142,
|
||||
};
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(People::ePeople);
|
||||
|
||||
#endif
|
|
@ -4,9 +4,11 @@
|
|||
|
||||
#include "core/class_db.h"
|
||||
#include "impulsebase.h"
|
||||
#include "people.h"
|
||||
|
||||
void register_impulse_types() {
|
||||
ClassDB::register_class<ImpulseBase>();
|
||||
ClassDB::register_class<People>();
|
||||
}
|
||||
|
||||
void unregister_impulse_types() {
|
||||
|
|
|
@ -233,7 +233,7 @@ void StateConnectionSynchronize::receive_system_sync(Ref<BitStream> msgin)
|
|||
this->_data->_server_sync = latestsync;
|
||||
this->_data->_synchronize = synchronize;
|
||||
this->_data->_current_server_tick = this->_data->_synchronize + this->_data->_current_received_number + 2;
|
||||
this->_data->_current_client_tick = this->_data->_current_server_tick + (LCT + this->_data->_ms_per_tick) / this->_data->_ms_per_tick;
|
||||
//this->_data->_current_client_tick = this->_data->_current_server_tick + (LCT + this->_data->_ms_per_tick) / this->_data->_ms_per_tick;
|
||||
this->_data->_current_client_time = this->_data->_update_time - (LCT + this->_data->_ms_per_tick);
|
||||
//this->_state = STATE::Synchronize;
|
||||
}
|
||||
|
@ -412,7 +412,8 @@ void StateConnectionConnected::send_normal_message()
|
|||
if (ele > 0)
|
||||
{
|
||||
DBG_PRINT("Send message");
|
||||
msgout.put_uint32(this->_data->_current_server_tick); // Cycle
|
||||
//msgout.put_uint32(this->_data->_current_server_tick); // Cycle
|
||||
msgout.put_uint32(++this->_data->_current_client_tick); // Increase Cylce and send with new value
|
||||
DBG_PRINT("msgout E:" + msgout.show_detail());
|
||||
msgout.put_uint8(ele);
|
||||
DBG_PRINT("msgout F:" + msgout.show_detail());
|
||||
|
@ -499,7 +500,7 @@ void StateConnectionConnected::receive_system_sync(Ref<BitStream> msgin)
|
|||
this->_data->_server_sync = latestsync;
|
||||
this->_data->_synchronize = synchronize;
|
||||
this->_data->_current_server_tick = this->_data->_synchronize + this->_data->_current_received_number + 2;
|
||||
this->_data->_current_client_tick = this->_data->_current_server_tick + (LCT + this->_data->_ms_per_tick) / this->_data->_ms_per_tick;
|
||||
//this->_data->_current_client_tick = this->_data->_current_server_tick + (LCT + this->_data->_ms_per_tick) / this->_data->_ms_per_tick;
|
||||
this->_data->_current_client_time = this->_data->_update_time - (LCT + this->_data->_ms_per_tick);
|
||||
//this->_state = STATE::Synchronize;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue