R
roblox-ts6mo ago
Ego*

Matter Client Structure

so i am working on a tower defense game, and the enemies entities movement is fully handled on the server and the client just gets the result every 6 frames (aka 10 times a second) but i am not sure how to structure that, currently in my world starting client script i just listen to the remote event that has the enemies new positions that are sent from the server i then add it to the client enemy entities through a component and there is a system that just moves enemies to that target position, my issue is that i would like to have a system that handles that instead of having to use a script to get the new positions then a system to move them
12 Replies
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
Ego*
Ego*OP6mo ago
sorry i was sleeping this is the replication system from the server
import { AnySystem, World } from "@rbxts/matter";
import { ServerEvents } from "Server/Modules/ServerNetworking";
import { EnemyPacketSerializer } from "Shared/CoreLibs/BinarySerializers";
import { EnemyInfo } from "Shared/CoreLibs/Components/EntityInfo";
import Enumerators from "Shared/CoreLibs/Enumerators";

const Frequency = 1/10 /// 0.1 Seconds

let LastIteration = 0
let Elapsed = 0

const EntitiesReplication = (World: World): void => {
const deltaTime = os.clock() - LastIteration;

Elapsed += deltaTime;
LastIteration = os.clock()

if (Elapsed < Frequency) {
return;
};

Elapsed = 0;

const EnemiesPackets = new Map<number, buffer>();

for (const [id, EntityEnemyInfo] of World.query(EnemyInfo)) {
const EnemyPacket = EnemyPacketSerializer.serialize({
T: EntityEnemyInfo.PathProgress,
Health: EntityEnemyInfo.Health,
});

EnemiesPackets.set(id, EnemyPacket.buffer);
}

ServerEvents.ReplicateEnemies.broadcast(EnemiesPackets);
};

export = {
system: EntitiesReplication,
priority: Enumerators.SystemPriorty.High,
event: "default",
} as AnySystem;
import { AnySystem, World } from "@rbxts/matter";
import { ServerEvents } from "Server/Modules/ServerNetworking";
import { EnemyPacketSerializer } from "Shared/CoreLibs/BinarySerializers";
import { EnemyInfo } from "Shared/CoreLibs/Components/EntityInfo";
import Enumerators from "Shared/CoreLibs/Enumerators";

const Frequency = 1/10 /// 0.1 Seconds

let LastIteration = 0
let Elapsed = 0

const EntitiesReplication = (World: World): void => {
const deltaTime = os.clock() - LastIteration;

Elapsed += deltaTime;
LastIteration = os.clock()

if (Elapsed < Frequency) {
return;
};

Elapsed = 0;

const EnemiesPackets = new Map<number, buffer>();

for (const [id, EntityEnemyInfo] of World.query(EnemyInfo)) {
const EnemyPacket = EnemyPacketSerializer.serialize({
T: EntityEnemyInfo.PathProgress,
Health: EntityEnemyInfo.Health,
});

EnemiesPackets.set(id, EnemyPacket.buffer);
}

ServerEvents.ReplicateEnemies.broadcast(EnemiesPackets);
};

export = {
system: EntitiesReplication,
priority: Enumerators.SystemPriorty.High,
event: "default",
} as AnySystem;
Ego*
Ego*OP6mo ago
this is the client script which starts the world, but it also has two functions which connect to the remote events of adding new enemy, and replicating enemies' new data
Ego*
Ego*OP6mo ago
and this is the system on the client which handles moving the enemeis (still unfinished)
import { AnySystem, World } from "@rbxts/matter";
import MapPath from "Shared/BezierPath";
import { Character } from "Shared/CoreLibs/Components/Character";
import { EnemyInfo } from "Shared/CoreLibs/Components/EntityInfo";
import { SystemPriorty } from "Shared/CoreLibs/Enumerators";

const PathLength = MapPath.PathLength;
const EnemyBaseSpeed = 4;

const EnemyMovement = (World: World) => {
for (const [id, EntityEnemyInfo, EntityCharacter] of World.query(EnemyInfo, Character)) {
const StepDistance = (EntityEnemyInfo.Speed * EnemyBaseSpeed) / PathLength;
const newT = math.min(
EntityEnemyInfo.PathProgress + StepDistance / 60,
EntityEnemyInfo.TargetPathProgress as number,
);

EntityCharacter.Model.PivotTo(MapPath.CalculateUniformCFrame(newT));
World.insert(id, EntityEnemyInfo.patch({ PathProgress: newT }));
}
};

export = {
system: EnemyMovement,
priority: SystemPriorty.Critical,
event: "fixed",
} as AnySystem;
import { AnySystem, World } from "@rbxts/matter";
import MapPath from "Shared/BezierPath";
import { Character } from "Shared/CoreLibs/Components/Character";
import { EnemyInfo } from "Shared/CoreLibs/Components/EntityInfo";
import { SystemPriorty } from "Shared/CoreLibs/Enumerators";

const PathLength = MapPath.PathLength;
const EnemyBaseSpeed = 4;

const EnemyMovement = (World: World) => {
for (const [id, EntityEnemyInfo, EntityCharacter] of World.query(EnemyInfo, Character)) {
const StepDistance = (EntityEnemyInfo.Speed * EnemyBaseSpeed) / PathLength;
const newT = math.min(
EntityEnemyInfo.PathProgress + StepDistance / 60,
EntityEnemyInfo.TargetPathProgress as number,
);

EntityCharacter.Model.PivotTo(MapPath.CalculateUniformCFrame(newT));
World.insert(id, EntityEnemyInfo.patch({ PathProgress: newT }));
}
};

export = {
system: EnemyMovement,
priority: SystemPriorty.Critical,
event: "fixed",
} as AnySystem;
.
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
Ego*
Ego*OP6mo ago
what's wrong ? is it that bad ? anyone can help me with this please ?
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
Ego*
Ego*OP6mo ago
what about the event of that system ? what should i set it as ?
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
Ego*
Ego*OP6mo ago
but wouldn't that make the system run each frame ? I'm not quite sure i get what you mean
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
Ego*
Ego*OP6mo ago
alright i will try that thanks for the help <3 but i don't think it works with flamework networking remote events ? since i remember matter system event required Connect, Once, ConnectParallel, Wait Methods, but the library doesn't have them

Did you find this page helpful?