سننظر في هذه المقالة في نقل البيانات بين الخادم والعميل في Unreal Engine 4 الذي تم تنفيذه في C ++ . في البداية ، بالنسبة لشخص ليس لديه تعليم متخصص ، يبدو أن هذا شيء معقد بشكل غير مفهوم. على الرغم من العدد الكبير من الأمثلة والتحليلات ، فقد كان من الصعب للغاية بالنسبة لي شخصياً أن أقوم بتجميع صورة كاملة لهذه العملية. ولكن ، عندما تم الوصول إلى الكمية الحرجة من المعلومات التي تم الحصول عليها من خلال القراءة والاختبارات ، تم التوصل إلى فهم لكيفية عمل كل هذا.
بادئ ذي بدء ، تحتاج إلى أن تفهم بوضوح أن جميع الكائنات في اللعبة (مع استثناءات نادرة) يمكن أن يكون لها نسخ متعددة. الكائن الأصلي موجود على الخادم. الأصل موجود دائما. يمكن أن توجد نسخ على العملاء ، ولكن ليس على الإطلاق ، أي قد لا تكون. تحدث جميع الأحداث الهامة على الخادم ، وهو الذي يقرر من يحتاج إلى معرفة ذلك ومن لا يفعل.
كل ما يحدث على العميل غير معروف لأي شخص باستثناء العميل. |
مثالنبدأ اللعبة مع اثنين من العملاء. يوجد مكعب على خشبة المسرح. أصل هذا المكعب موجود على الخادم. هو الأهم. سيتم وضع النسخة الأولى على العميل الأول ، والثانية - على العميل الثاني. إذا قمنا بشيء مع نسخة من الكائن على أي من عملائها ، فلن يعاني الأصل. سيكون التغيير محليًا بحتًا ، لهذا العميل فقط. إذا قمت بتغيير الأصل ، فهناك سيناريوهان رئيسيان:
- ستبقى نسخ العملاء دون تغيير.
- ستتم مزامنة نسخ العملاء مع النسخة الأصلية.
الآن بعد أن أصبحت القواعد الأساسية للعبة واضحة ، يمكننا أن نفكر في الخيارات المتاحة لإرسال المعلومات بين الخادم والعميل المتاحة لنا. أعرف 3 طرق ، لكننا سننظر فقط في الأولين ، لأن يسمح لك الثالث بنقل أي شيء على الإطلاق وفي أي مكان ، وينطبق فقط إذا كنت مقيدًا بقيود الأولين.
- تكرار
- RPC ( استدعاءات الإجراءات البعيدة ).
- TCP
تكرار
أول شيء يجب قبوله دون قيد أو شرط:
النسخ المتماثل هو طريق ذو اتجاه واحد ، ويعمل فقط من الخادم إلى العميل. |
الشيء الثاني الذي تحتاج إلى معرفته:
يمكن فقط نسخ الكائنات أو متغيرات الفئة. |
وثالثًا ، شرط مهم:
يحدث النسخ المتماثل فقط عند حدوث تغيير على الخادم. |
إذا قمنا في
Blueprint فقط بتحديد الأماكن المناسبة ، فإن
C ++ ليس أكثر تعقيدًا.
الشيء الرئيسي
هو عدم نسيان تضمين
#include "UnrealNetwork.h" .
أولاً ، ضع في الاعتبار نسخ الكائن.
في المنشئ نكتب:
bReplicates = true;
إذا أردنا تكرار الحركة:
bReplicateMovement = true;
إذا كنت بحاجة إلى نسخ المكون المتصل:
Component->SetReplicates(true);
يمكن العثور على وصف كامل هنا .
مع النسخ المتغير ، تكون الأشياء أكثر إثارة للاهتمام.
لنبدأ بملف رأس .h .
يمكنك ببساطة نسخ المتغير:
UPROPERTY(Replicated) bool bMyReplicatedVariable;
أو يمكنك تشغيل بعض الوظائف على جانب العميل إذا تم نسخ المتغير. لا يهم القيمة التي يأخذها المتغير. حقيقة تغييره مهمة.
UPROPERTY(ReplicatedUsing = OnRep_MySomeFunction) TArray<float> MyReplicatedArray; UFUNCTION() void OnRep_MySomeFunction();
يعد تشغيل إحدى الوظائف مجرد إحدى طرق إرسال الأوامر من الخادم. من المهم جدًا معرفة أن تكرار المصفوفات لا يحدث بالكامل ، ولكن فقط الجزء المتغير. وبالتالي ، باستخدام متغير واحد فقط ، يمكنك إرسال العديد من الأوامر من الخادم ، مع تحليل الصفيف إلى عناصر ، والعناصر إلى وحدات بت.
الآن دعنا ننتقل إلى .cpp
نكتب شروط النسخ المتماثل:
void AMySuperActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(AMySuperActor, bMyReplicatedVariable); DOREPLIFETIME_CONDITION(AMySuperActor, MyReplicatedArray, COND_OwnerOnly); }
تم نسخ المتغير الأول bMyReplicatedVariable دون قيد أو شرط لجميع العملاء في وقت واحد ، بينما تم تحديث المتغير الثاني MyReplicatedArray فقط للعميل الذي يملك كائن AMySuperActor ، إلا إذا تم الإعلان عنه بالطبع.
يمكن العثور على قائمة كاملة بالظروف المحتملة هنا .
RPC ( استدعاءات الإجراءات البعيدة )
هذه الطريقة في نقل البيانات ، على عكس النسخ المتماثل ، تعمل في كلا الاتجاهين ، ولكنها أكثر تكلفة. لاستخدامه ، ما عليك سوى ربط # تتضمن "UnrealNetwork.h" .
ميزة مهمة هي أنه يمكنك نقل المتغيرات باستخدام طريقة RPC . |
أولاً ، يجب أن يقال أن RPCs تأتي مع إقرار باستلام
موثوق به وبدون
موثوق به . إذا لم يهدأ المرسل في الحالة الأولى حتى يقتنع بأنه تم تسليم الطرد (وسوف يرسله مرارًا وتكرارًا إذا لم يكن هناك أخبار متبادلة) ، ففي الحالة الثانية ، لا يهتم المرسل إذا تلقى شخص الطرد أم لا. أرسل ونسيت.
حيثما أمكن - استخدم "
غير موثوق به" . عادة ما تكون هذه الطريقة مناسبة للمعلومات غير المهمة للغاية ، أو للبيانات التي يتم تحديثها بشكل متكرر. عندما يكون من المستحيل ، في حالة الإرسال من الخادم إلى العميل ، نحاول القيام بالنسخ المتماثل مع استدعاء دالة ، كما هو موضح أعلاه.
لذا ، لإرسال الحزمة الخاصة بنا من العميل إلى الخادم ، تحتاج إلى تسجيل ثلاث وظائف:
UFUNCTION(Reliable, Server, WithValidation) void ServerTestFunction(float MyVariable); void ServerTestFunction_Implementation(float MyVariable); bool ServerTestFunction_Validate(float MyVariable);
موثوقة - طرد مع إقرار بالاستلام.
الخادم - الإرسال من العميل إلى الخادم.
WithValidation - يتم فتح الحزمة من قبل المستلم فقط في حالة استيفاء الشروط الموضحة في وظيفة ServerTestFunction_Validate (تعويم MyVariable) . أي إذا أعيدت الدالة صحيحة . هذه المعلمة مطلوبة فقط للوظائف التي يتم تنفيذها على الخادم.
ServerTestFunction (Float MyVariable) - يتم استدعاء هذه الوظيفة من قبل العميل إذا كان يريد إرسال شيء إلى الخادم. بشكل عام ، ليس مطلوبًا حتى وصفه في .cpp .
ServerTestFunction_Implementation (تعويم MyVariable) - سيتم استدعاء هذه الوظيفة مباشرة على الخادم فقط إذا ...
ServerTestFunction_Validate (تعويم MyVariable) - يتم تنفيذ هذه الوظيفة على الخادم ، وإذا تم إرجاع true ، فسيتم استدعاء ServerTestFunction_Implementation (تعويم MyVariable) .
لإرسال حزمة من الخادم إلى العميل ، إذا لم نكن سعداء بشكل قاطع باستخدام النسخ المتماثل ، في جوهره فقط يتغير الخادم إلى العميل :
UFUNCTION(Reliable, Client, WithValidation)
يمكن أن تكون أسماء الوظائف ، من حيث المبدأ ، تعسفية ، ولكن يجب أن تعكس في العادة إلى أين تتجه الحزمة. لراحتنا.
UFUNCTION(Reliable, Client, WithValidation) void ClientTestFunction(float MyVariable); void ClientTestFunction_Implementation(float MyVariable); bool ClientTestFunction_Validate(float MyVariable);
وإلا ، فإنها تعمل بنفس الطريقة تمامًا كما في المثال السابق ، مع الأخذ في الاعتبار حقيقة أن الحزمة هذه المرة تنتقل من الخادم إلى العميل.
هناك خيار آخر للإرسال من الخادم ، عندما تنتقل الحزمة إلى جميع العملاء في وقت واحد.
UFUNCTION(Reliable, NetMulticast, WithValidation) void NetMulticastTestFunction(); void NetMulticastTestFunction_Implementation(); bool NetMulticastTestFunction_Validate();
لا تسيء استخدام هذا الخيار. فكر في كيفية إدارة النسخ المتماثل.
بالنسبة للعميل و NetMulticast ، فإن التحقق اختياري |
مثال على تنفيذ طلب الخادم void ADreampaxActor::DoSomethingWithOtherActor(ADreampaxOtherActor * SomeOtherActor) { if (Role < ROLE_Authority) { ServerDoSomethingWithOtherActor(SomeOtherActor); return; } SomeOtherActor->Destroy(true); } void ADreampaxCharacter::ServerDoSomethingWithOtherActor_Implementation(ADreampaxOtherActor * SomeOtherActor) { DoSomethingWithOtherActor(SomeOtherActor); } bool ADreampaxCharacter::ServerDoSomethingWithOtherActor_Validate(ADreampaxOtherActor * SomeOtherActor) { return true; }
وأخيرًا ، رابط إلى الدليل ، والذي يجب قراءته.
خلاصة الشبكة "Unreal Engine 4"
هذا كل ما تحتاج لمعرفته حول الاتصال بين الخادم والعميل من أجل المتابعة إلى القسم التالي ، حيث سنكتب نسخة متكررة من المخزون ونفكر في كيفية إجراء التغييرات عليه بشكل صحيح.
ملاحظة: إذا لاحظت أي أخطاء أو أخطاء ، يرجى الكتابة في التعليقات.