Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,79 @@ You can also cancel the change of a property can calling `networkCancelProperty(

The whole set of currently shared network objects can be saved using host.saveState() and loaded using host.loadState(bytes). It uses the versionning decribed previously. Once loaded, call host.makeAlive() to make sure all alive() calls are made to object.


### Visibility

It is possible to filter which clients an object's properties will be synced to. To enable this, compile with `-D hxbit_visibility`, and define the available groups by adding this macro to your hxml file:

```haxe
--macro hxbit.Macros.initVisibility(["owner", "sameRoom"]) // The group names can be anything you want
```

We also need to implement a `rootObject`, which will reference all objects (objects not part of it wont be synced to clients):
```haxe
// Example player class
class Player extends hxbit.NetworkSerializable {
public function new(client: hxbit.NetworkHost.NetworkClient) {
client.ownerObject = this;
enableReplication = true;
}
}

class RootObject extends hxbit.NetworkSerializable {
@:s public var players: Array<Player> = [];
public function new(client: hxbit.NetworkHost.NetworkClient) {
client.ownerObject = this;
enableReplication = true;
}
}
```

Then set this as the root object on the server, and enable `lateRegistration`:

```haxe
var host = new NetworkHost();
var rootObject:RootObject;

...

host.lateRegistration = true; // Also has to be set to true on clients

host.wait('0.0.0.0', 9999, (client) -> {
trace('player connected');
rootObject.players.push(new Player(client));
});

rootObject = new RootObject(host.self);
host.rootObject = rootObject;
```

Now, for example, if we want a certain property to only be synced between the host and the client that owns the object, we add the following attribute to it:

```haxe
@:s @:visible(owner) public var ownProperty: Int;
```

And then add the an `evalVisibility` method to the class:
```haxe
public override function evalVisibility(group: hxbit.VisibilityGroup, from: hxbit.NetworkSerializable): Bool {
if (group == Owner) { // The group owner was declared using the macro above
return from == this;
}

// Example for syncing properties only if clients are in the same room
if (group == SameRoom) {
return this.roomId == from.roomId;
}

return true;
}
```

If `ownProperty` is modified, it will only be synced between the host and owner, on every other client it will be `null`.

The visibility can be revalidated by calling the method `setVisibilityDirty(GroupName);`.
An example of this would be if a property is only visible for clients in the same room, or a property that is only
available to nearby players.

Note: make sure to call `host.makeAlive()` frequently on the clients, otherwise new objects wont appear until a RPC is called on them.
8 changes: 6 additions & 2 deletions hxbit/Macros.hx
Original file line number Diff line number Diff line change
Expand Up @@ -2047,9 +2047,13 @@ class Macros {

var conds = new haxe.EnumFlags<Condition>();
conds.set(PreventCDB);
for( m in r.f.meta )
var visibilityMask = 0;
for( m in r.f.meta ) {
if( m.name == ":allowCDB" )
conds.unset(PreventCDB);
if( m.name == ":visible" )
visibilityMask |= 1 << getVisibility(m);
}

if( returnVal.value || returnVal.call ) {
var typeValue;
Expand Down Expand Up @@ -2085,7 +2089,7 @@ class Macros {
}

var forwardRPC = macro {
@:privateAccess __host.doRPC(this,$v{id},$resultCall, function(__ctx) {
@:privateAccess __host.doRPC(this,$v{id}, $v{visibilityMask}, $resultCall, function(__ctx) {
$b{[
for( a in funArgs )
withPos(macro hxbit.Macros.serializeValue(__ctx, $i{a.name}), f.expr.pos)
Expand Down
9 changes: 8 additions & 1 deletion hxbit/NetworkHost.hx
Original file line number Diff line number Diff line change
Expand Up @@ -638,12 +638,19 @@ class NetworkHost {
return targetClient != null; // owner not connected
}

inline function doRPC(o:NetworkSerializable, id:Int, onResult:NetworkSerializer->Void, serialize:NetworkSerializer->Void) {
inline function doRPC(o:NetworkSerializable, id:Int, visibilityMask: Int, onResult:NetworkSerializer->Void, serialize:NetworkSerializer->Void) {
beforeRPC(o,id);
#if hxbit_visibility
for( c in clients ) {
var ctx = c.ctx;
if( targetClient != null && targetClient != c ) continue;

if ( isAuth && visibilityMask != 0 && c.ownerObject?.__cachedVisibility != null ) {
var visibility = c.ownerObject.__cachedVisibility.get(o);
if ( visibility & visibilityMask == 0 ) {
continue;
}
}
#end
var rpcPosition = beginRPC(ctx, o, id, onResult);
#if hxbit_visibility
Expand Down