-
Notifications
You must be signed in to change notification settings - Fork 0
Script Engine
- Game Loop
-
Scripting
- Script Classes
- Script Attributes
- Editor
- UI
- Network
- Controller
- Networking
- Connection, Relevance and Roles
- Field Replication
- Method Replication (RPC)
- C# calls static methods in the convention
Namespace.Class.Subclass.Method(parameters), however to distinguish namespaces from class scopes, methods and fields, in this documentation it is written asNamespace.Class::Subclass::Method(parameters)(similar to C++ scope style). - Certain words are written in bold to stand out, avoiding confusion or error with certain concepts by grabbing your eye’s attention.
- Shard3D runs with a single threaded game loop, everything gets called in a defined order, however it is planned to separate the game logic and physics from the renderer (1 game thread, 1 renderer thread).
- Renderer calls always get called at the end of the loop
- Physics runs with a fixed step rate configurable in the engine_settings.ini (default is 120Hz). It may run multiple times per frame or it may even skip a frame! (depending on the framerate)
- When physics is stepped in a frame, it's done before the C# script step except for
LLevel::PrePhysicsTickEvent(float ts)(Shard3D.Scriptable) (this also means that fixed tick methods will be called before their variable tick counterparts) - Physics body transform interpolation occurs every frame after physics step (if occurred) and before script engine step (this also means before the fixed step events)
-
Scripts derive from 3 base classes:
LLevel,LGameMode,AActor(Shard3D.Scriptable) -
L is the prefix stating it’s a singleton inside the level, thus there may only be one instance.
-
A is the prefix stating it’s an actor, which is a scriptable prefab actor, it may have multiple instances.
-
AActor:
-
Is to be used standalone for any sort of script, whilst AController is used for input management (this distinction is made due to how the networking system is set up):
-
AController(InheritsAActor,IGhostActor,INetworkReplicatesServerOwner,INetworkOwnableActor)- Only this class and
UIControlshould be allowed to poll user inputs and manage renderer data - Spawned through
new T()(whereTis a class derived fromAController) - Controllers will be automatically destroyed at the end of the level, however you can destroy them earlier using
Level.KillController<T>()
- Only this class and
-
-
BeginEvent()(called when level simulation starts, only called once solely for actors that already existed before the level started simulation!) -
EndEvent()(called when the level simulation ends, only called once solely for actors that survived until the end of the simulation!) -
SpawnEvent()(called when actor is spawned) -
KillEvent()(called when actor is destroyed) -
TickEvent(float dt)(called every game loop frame, is not stable, as it has a variable delta time and should be used when integration can be done with a variable frame time) -
PhysicsTickEvent(float ts)(called at the same rate as the physics step, may be called several times per frame, or it may be skipped in a frame as it runs at a fixed step rate, should be used for integration that requires a fixed time step. Warning, this does not mean that the values get interpolated like the physics positions do, if interpolation between steps is requires, you should do that in a variable frametime tick event (e.g.AActor::TickEvent(),LLevel::PostTickEvent()))
-
-
LLevel:
- Is set in the WorldSceneInfoComponent
- BeginEvent() (called before any other begin event, it is the first event called)
- EndEvent() (called after every end event, it is the last event called)
- PreTickEvent(float dt) (called before any AActor::TickEvent(float dt))
- PostTickEvent(float dt) (called after every AActor::TickEvent(float dt))
- PrePhysicsTickEvent(float ts) (called before any AActor::PhysicsTickEvent(float ts) and before regular tick events)
- PostPhysicsTickEvent(float ts) (called after every AActor::PhysicsTickEvent(float ts) and before regular tick events)
-
LGameMode
- Is set in the WorldSceneInfoComponent
- N is the prefix stating it is a networking related method
- NClientConnectingEvent(AController controller) (client has connected and their respective default controller prefab)
- NClientDisconnectedEvent(AController controller) (client has disconnected)
- The script api provides 2 kinds of attributes, attributes are only used by derived classes of AActor and UIControl, one purely flag oriented kind by inheriting an empty interface (so that it gets passed onto derived classes, e.g.
public class MyBaseClass : ITestAttribute) and another property oriented kind that work like C# attributes (e.g.[MyAttribute]or[MyOtherAttribute(true)])
- Shard3D offers the ability for fields to be edited in editor, this allows for multiple instances to have different parameters at edit time, being loaded from the scene file at runtime. It also offers the ability for (exclusively useful for editor) calling methods in the editor (without input parameters or return types!)
- Attributes (
Shard3D.Reflection):ExposeField(bool editable = true)ExposeMethod(bool requirePlayMode = true)NumericFieldEditProperties(double min = -INFINITY, double max = INFINITY, double speed = 1.0)
-
[ExposeField(bool)]may only be applied on top of the following types:- (of
System)float,double, (u)byte, (u)short, (u)int, (u)long,string - (of
Shard3D.Library.Types)Float2,Float3,Float4,Float3x3,Float4x4 - (of
Shard3D)Actor(This includes all classes derived from Actor)
- (of
-
[NumericFieldEditProperties(double, double, double)]may be applied on numeric fields that have the[ExposeField]attribute withbool editableset to true.
-
These attributes are only used on the new
RmlDocumentclass (fromShard3D.UI.Rml) - As RmlUi supports scripting through Lua, basic interop is possible between C# and Lua
- Attributes (
Shard3D.UI.Rml.Lua):-
[RmlLuaAccessible(string accessAs)]defines the name where the Lua script in the document can be accessed as -
[RmlLuaMethod]exposes the method to the Lua script. Onlyfloat,double, (u)byte, (u)short, (u)int, (u)long,stringare supported as input parameters -
[RmlLuaField]exposes the field to the Lua script`)
-
- Recent Shard3D Torque versions support RmlUi data bindings. Data bindings are used through use of Data models. To create a data model, create a class that inherits from
RmlDataModel(Shard3D.UI.Rml.Data)-
[RmlDataVariable]is to be placed on a field. This may be a primitive type, RmlColor, Float2,3,4, or string. Data conversion is automatically performed whenever possible. In case of an invalid conversion, the default value is provided. This attribute may also be placed on a field who's type is a class implementingIRmlDataScalar,IRmlDataArrayorIRmlDataStruct. XML documentation is provided for those interfaces.
-
- Networking is enabled through setting attributes on fields, methods and classes.
- Networking attributes through interfaces:
INetworkOwnableActor,INetworkReplicatesEveryone,INetworkReplicatesServerOwner. These attributes may be applied on a base class and their “attribute flag” will be passed down. - Networking attributes through
System.Attribute:NetworkReplicateField(uint Size, float maxHZ, NetworkReplicationFlags ReplicationFlags = NetworkReplicationFlags.SendEveryone)(for use on fields),NetworkReplicateFieldNotifier(string FieldName)(for use on methods to connect to fields with the[NetworkReplicateField]attribute),NetworkReplicableActor(NetworkReplicationRelevance Relevance = NetworkReplicationRelevance.NotRelevant, float Priority = 1.0f, float CullDistanceMeters = 10000.0F)(for use on classes deriving from AActor),RemoteProcedureCall(RemoteProcedureCallBroadcast Broadcast, RemoteProcedureCallReliability Reliability = RemoteProcedureCallReliability.Unreliable)(for use on methods) (Shard3D.Networking) -
INetworkOwnableActorsignifies an actor that can be owned, e.g. a controller, pawn, or client relative actor. This does not mean that a client has authority over the actor, the server should always have ultimate authority over replicated actors. -
[NetworkReplicableActor(NetworkReplicationRelevance, float, float)]is an attribute to be applied on classes that inherit AActor. This will enable the actor to make use of the networking replication API.- NetworkReplicationRelevance (currently unused) defines the relevance of the actor. The boundary of relevance is determined by the
CullDistanceMetersparameter, which is the maximum cull distance between the possessed camera and possessed pawn.NotAlwaysRelevantstates that the actor may not be relevant, once out of the cull range it is considered not relevant, and replication priority is low or even disabled.AlwaysRelevantwill force the actor to always be replicated.OnlyOwnerRelevantwill only force replication on server and owning client, it is treated asNotAlwaysRelevanton the rest of the clients. -
Priority(currently unused) defines the relative replication priority. -
CullDistanceMeters(currently unused) defines the bounding radius when relevance alters.
- NetworkReplicationRelevance (currently unused) defines the relevance of the actor. The boundary of relevance is determined by the
-
[NetworkReplicateField(uint, float, float, NetworkReplicationFlags, NetworkReplicationQuantization)]is an attribute to be applied on fields (of type: float, double, (u)byte, (u)short, (u)int, (u)long, and every unmanaged struct) of actors with the[NetworkReplicableActor]attribute-
uint Sizestates the static size of the field. Only the server may replicate variables back to the client(s). -
float maxHZstates the maximum update rate of that field (note thus that in this case fields only replicate when their value has changed between their respective checks!). Warning: fields may not successfully replicate to clients as the network packets are sent as low priority and unreliable as field replication gets updated relatively frequently, if a client has an unstable connection it may fail to receive the most up-to-date value! For updating values crucially (but infrequently) prefer using a Remote Procedure Call. -
float minHZstates the constant update rate of the field, the server will periodically replicate the variable according to this parameter, so use it sparingly! -
NetworkReplicationFlags ReplicationFlagsdefines to whom the variable may be replicated (SendOwner replicates from server to the client who owns the actor, SendExceptOwner replicates from server to everyone except the client who owns the actor. These 2 flags are combined in SendEveryone, which replicates to everyone). -
NetworkReplicationQuantization Quantizationis used on numeric values, including the FloatN types ofShard3D.Library.Types, each type is used for compressing values to reduce network bandwidth usage (especially useful for variables that change in mass a lot)
-
-
NetworkReplicateFieldNotifier(string)(currently unused) is an attribute to be used in junction with[NetworkReplicateField]who’s method will be called when the named field is replicated.-
string FieldNameis the name of the field that will trigger the event.
-
- [RemoteProcedureCall(RemoteProcedureCallBroadcast, RemoteProcedureCallReliability)] is an attribute to be applied on methods, either static, or non-static inside of classes deriving from AActor with the
[NetworkReplicableActor]attribute.-
RemoteProcedureCallBroadcastsets to who the RPC may be called to (Clientreplicates from server to the client who owns the actor,Serverreplicates from the calling client to the server,Universalcalls the function locally and replicates the function to all clients (only allowed to be called by server, clients currently do not have the ability to call a Universal RPC).) -
RemoteProcedureCallReliabilityconfigures the packet reliability. By default this is set toUnreliable(UDP) which means the function is not guaranteed to make it to the remote connection.Reliable(TCP) RPC’s will guarantee making it to the remote connection and in defined order, however it is not recommended to make use of too many reliable RPC’s as it can congest the server or client. Examples for when to mark a method as unreliable:- It has no gameplay impact
- It may be called extremely frequently
-
- Shard3D now supports mapping input via attributes on fields, properties and methods. When mapped, the engine will deal with the mapping and automatically bind the appropriate calls on the event that an input is triggered.
-
Network::ConnectToRemoteHost(AController requestingController, string ipv4, ushort port = 5400)(fromShard3D.Networking) is a method to connect to a remote host:-
AController requestingControlleris the client's controller that the server will be able to connect with. -
string ipv4is the IPv4 address encoded in a string (it may not be a domain address!) of the host. Set as “127.0.0.1” to connect to your own machine. Local IP addresses (192.168.xxx.xxx) can be connected to if the connecting machine and server are on the exact same network. -
ushort portis the port of the remote host (defined in serverconfig/server_settings.ini). Default is 5400.
-
-
NetworkConnectionStatusDelegate ConnectionStatusDelegate(fromShard3D.Networking) is a callback that will be called when changes are made with the host's connection (void NetworkConnectionStatusDelegate(NetworkConnectionStatus status)is the callback's signature)-
NetworkConnectionStatus statusis the new status of the reported connection result
-
-
NetworkRole Network::Role(fromShard3D.Networking) will return:-
ILLEGALif there is no connection -
Authorityif the script is running in the server -
Clientif the script is running in the client and has an active connection with the server
-
- Fields are only replicated by the server through UDP, this means that when a field replication occurs, only when the server sets the variable will it replicate to all clients. This is both due to that clients cannot see other clients (which would encourage bad design choices related to networking security), and to prevent easy exploits where the server is not able to check the values that are set.
- RPC’s are extremely useful to reproduce steps across connections.
- To create a RPC:
- Define a method (preferably prefixed with RPC or an indicator that it is a remote procedure call, as well as to whom it shall be replicated e.g. RPCToClient_MyMethod(int foo)) and apply the
[RemoteProcedureCall]attribute. - Create another method with the exact same input parameters, and exact same name, suffixed with _Impl e.g.
RPCToClient_MyMethod_Impl(int foo)with no attributes, and implement your code in there. If your remote procedure call is of broadcast typeServer, an optional auto generated first input parameter isRemoteConnectionHandle(fromShard3D.Networking) e.g.RPCToServer_Impl(RemoteConnectionHandle who, int test); - Inside the RPC defined method (not the implementation method) initialise a variable with the
static Network::CreateRPC(AActor instance = null)method (fromShard3D.Networking). (DO NOT CALL THIS THROUGH A HELPER METHOD!! Call it directly inside the RPC defining method! This method uses reflection to automatically determine what class and what method is defining the RPC!). You may provide anAActorinstance in case your RPC is defined inside an instantiated actor. Leave as null if your method is static. The builder is to be used as follows:-
AddParameter<T>(T param)(T of type string or any unmanaged type) adds a parameter in order to the network packet. -
SetPrefabUUIDSyncCount(uint count)sets the amount of prefab creations needing their UUID’s synchronised within the remote procedure call. Make sure this value is the exact quantity of synchronised UUIDs necessary as any disjunction can cause errors with UUID synchronisation in other methods! This is accompanied with theNetwork::PopPrefabSyncUUID(bool discard = false)method which synchronises the next spawned prefab’s UUID in order, which should be called right before spawning a prefab! -
Call()sends the RPC to the remote connection (and automatically calls locally if the RPC is broadcast universally)
-
- Define a method (preferably prefixed with RPC or an indicator that it is a remote procedure call, as well as to whom it shall be replicated e.g. RPCToClient_MyMethod(int foo)) and apply the