mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-10-03 03:31:28 +03:00
Sync cleanup + player-local entities/labels
This commit is contained in:
@@ -114,11 +114,6 @@ public class NetServer implements ApplicationListener{
|
|||||||
public static float voteDuration = 0.5f * 60;
|
public static float voteDuration = 0.5f * 60;
|
||||||
/** Cooldown between votes in seconds. */
|
/** Cooldown between votes in seconds. */
|
||||||
public static int voteCooldown = 60 * 5;
|
public static int voteCooldown = 60 * 5;
|
||||||
/**
|
|
||||||
* If this is true, isSyncHidden will called only once per team if FoW is enabled, or not at all.
|
|
||||||
* Set this to false if a mod uses isSyncHidden to hide entities.
|
|
||||||
*/
|
|
||||||
public boolean skipHiddenEntitiesCheck = true;
|
|
||||||
|
|
||||||
private ReusableByteOutStream writeBuffer = new ReusableByteOutStream(127);
|
private ReusableByteOutStream writeBuffer = new ReusableByteOutStream(127);
|
||||||
private Writes outputBuffer = new Writes(new DataOutputStream(writeBuffer));
|
private Writes outputBuffer = new Writes(new DataOutputStream(writeBuffer));
|
||||||
@@ -1116,48 +1111,6 @@ public class NetServer implements ApplicationListener{
|
|||||||
universe.seconds(), tps, GlobalVars.rand.seed0, GlobalVars.rand.seed1, syncStream.toByteArray());
|
universe.seconds(), tps, GlobalVars.rand.seed0, GlobalVars.rand.seed1, syncStream.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeEntitySnapshot(Player player) throws IOException{
|
|
||||||
syncStream.reset();
|
|
||||||
|
|
||||||
hiddenIds.clear();
|
|
||||||
int sent = 0;
|
|
||||||
|
|
||||||
for(Syncc entity : Groups.sync){
|
|
||||||
//TODO write to special list
|
|
||||||
if(entity.isSyncHidden(player)){
|
|
||||||
hiddenIds.add(entity.id());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//write all entities now
|
|
||||||
dataStream.writeInt(entity.id()); //write id
|
|
||||||
dataStream.writeByte(entity.classId() & 0xFF); //write type ID
|
|
||||||
entity.beforeWrite();
|
|
||||||
entity.writeSync(dataStreamWrites); //write entity itself
|
|
||||||
|
|
||||||
sent++;
|
|
||||||
|
|
||||||
if(syncStream.size() > maxSnapshotSize){
|
|
||||||
dataStream.close();
|
|
||||||
Call.entitySnapshot(player.con, (short)sent, syncStream.toByteArray());
|
|
||||||
sent = 0;
|
|
||||||
syncStream.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sent > 0){
|
|
||||||
dataStream.close();
|
|
||||||
|
|
||||||
Call.entitySnapshot(player.con, (short)sent, syncStream.toByteArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hiddenIds.size > 0){
|
|
||||||
Call.hiddenSnapshot(player.con, hiddenIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
player.con.snapshotsSent++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Does not check isSyncHidden. Call this if no entities are hidden. */
|
/** Does not check isSyncHidden. Call this if no entities are hidden. */
|
||||||
public void writeEntitySnapshotsAll() throws IOException{
|
public void writeEntitySnapshotsAll() throws IOException{
|
||||||
syncStream.reset();
|
syncStream.reset();
|
||||||
@@ -1165,11 +1118,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
int sent = 0;
|
int sent = 0;
|
||||||
|
|
||||||
for(Syncc entity : Groups.sync){
|
for(Syncc entity : Groups.sync){
|
||||||
//write all entities now
|
writeEntity(entity, dataStream);
|
||||||
dataStream.writeInt(entity.id()); //write id
|
|
||||||
dataStream.writeByte(entity.classId() & 0xFF); //write type ID
|
|
||||||
entity.beforeWrite();
|
|
||||||
entity.writeSync(dataStreamWrites); //write entity itself
|
|
||||||
|
|
||||||
sent++;
|
sent++;
|
||||||
|
|
||||||
@@ -1191,30 +1140,25 @@ public class NetServer implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Checks isSyncHidden for only one player per team. Called if FoW is enabled but there is no custom syncHidden. */
|
/** Checks isSyncHidden for only one player per team. Called if FoW is enabled but there is no custom syncHidden. */
|
||||||
public void writeEntitySnapshotsTeam(Seq<Player> players) throws IOException{
|
public void writeEntitySnapshotsTeam(Team team, Seq<Player> players) throws IOException{
|
||||||
syncStream.reset();
|
syncStream.reset();
|
||||||
|
|
||||||
hiddenIds.clear();
|
hiddenIds.clear();
|
||||||
int sent = 0;
|
int sent = 0;
|
||||||
|
|
||||||
for(Syncc entity : Groups.sync){
|
for(Syncc entity : Groups.sync){
|
||||||
//TODO write to special list
|
if(entity.isSyncHidden(team)){
|
||||||
if(entity.isSyncHidden(players.first())){
|
|
||||||
hiddenIds.add(entity.id());
|
hiddenIds.add(entity.id());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//write all entities now
|
writeEntity(entity, dataStream);
|
||||||
dataStream.writeInt(entity.id()); //write id
|
|
||||||
dataStream.writeByte(entity.classId() & 0xFF); //write type ID
|
|
||||||
entity.beforeWrite();
|
|
||||||
entity.writeSync(dataStreamWrites); //write entity itself
|
|
||||||
|
|
||||||
sent++;
|
sent++;
|
||||||
|
|
||||||
if(syncStream.size() > maxSnapshotSize){
|
if(syncStream.size() > maxSnapshotSize){
|
||||||
dataStream.close();
|
dataStream.close();
|
||||||
final var ssent = (short)sent;
|
short ssent = (short)sent;
|
||||||
var bytes = syncStream.toByteArray();
|
var bytes = syncStream.toByteArray();
|
||||||
players.each(player -> Call.entitySnapshot(player.con, ssent, bytes));
|
players.each(player -> Call.entitySnapshot(player.con, ssent, bytes));
|
||||||
sent = 0;
|
sent = 0;
|
||||||
@@ -1224,7 +1168,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
|
|
||||||
if(sent > 0){
|
if(sent > 0){
|
||||||
dataStream.close();
|
dataStream.close();
|
||||||
final var ssent = (short)sent;
|
short ssent = (short)sent;
|
||||||
var bytes = syncStream.toByteArray();
|
var bytes = syncStream.toByteArray();
|
||||||
players.each(player -> Call.entitySnapshot(player.con, ssent, bytes));
|
players.each(player -> Call.entitySnapshot(player.con, ssent, bytes));
|
||||||
}
|
}
|
||||||
@@ -1236,6 +1180,40 @@ public class NetServer implements ApplicationListener{
|
|||||||
players.each(player -> player.con.snapshotsSent++);
|
players.each(player -> player.con.snapshotsSent++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Writes a custom snapshot containing player-local entities; this is for entities other players don't see. */
|
||||||
|
public void writeCustomEntitySnapshot(Player player, Iterable<Syncc> entities) throws IOException{
|
||||||
|
syncStream.reset();
|
||||||
|
|
||||||
|
int sent = 0;
|
||||||
|
|
||||||
|
for(Syncc entity : entities){
|
||||||
|
writeEntity(entity, dataStream);
|
||||||
|
|
||||||
|
sent++;
|
||||||
|
|
||||||
|
if(syncStream.size() > maxSnapshotSize){
|
||||||
|
dataStream.close();
|
||||||
|
Call.entitySnapshot(player.con, (short)sent, syncStream.toByteArray());
|
||||||
|
sent = 0;
|
||||||
|
syncStream.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sent > 0){
|
||||||
|
dataStream.close();
|
||||||
|
|
||||||
|
Call.entitySnapshot(player.con, (short)sent, syncStream.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeEntity(Syncc entity, DataOutputStream dataStream) throws IOException{
|
||||||
|
dataStream.writeInt(entity.id()); //write id
|
||||||
|
dataStream.writeByte(entity.classId() & 0xFF); //write type ID
|
||||||
|
entity.beforeWrite();
|
||||||
|
entity.writeSync(dataStreamWrites); //write entity itself
|
||||||
|
}
|
||||||
|
|
||||||
public String fixName(String name){
|
public String fixName(String name){
|
||||||
name = name.trim().replace("\n", "").replace("\t", "");
|
name = name.trim().replace("\n", "").replace("\t", "");
|
||||||
if(name.equals("[") || name.equals("]")){
|
if(name.equals("[") || name.equals("]")){
|
||||||
@@ -1291,7 +1269,6 @@ public class NetServer implements ApplicationListener{
|
|||||||
Groups.player.each(p -> !p.isLocal(), player -> {
|
Groups.player.each(p -> !p.isLocal(), player -> {
|
||||||
if(player.con == null || !player.con.isConnected()){
|
if(player.con == null || !player.con.isConnected()){
|
||||||
onDisconnect(player, "disappeared");
|
onDisconnect(player, "disappeared");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1300,29 +1277,25 @@ public class NetServer implements ApplicationListener{
|
|||||||
|
|
||||||
writeStateSnapshot();
|
writeStateSnapshot();
|
||||||
|
|
||||||
if(skipHiddenEntitiesCheck){
|
if(Vars.state.rules.fog){
|
||||||
if(Vars.state.rules.fog){
|
//Serialize by teams
|
||||||
//Serialize by teams
|
for(Team team : Team.all){ //Not Teams.active, because players can be on inactive teams
|
||||||
for(Team team : Team.all){ //Not Teams.active, because players can be on inactive teams
|
var tdata = team.data();
|
||||||
var tdata = team.data();
|
playersToSend.selectFrom(tdata.players, p -> !p.isLocal() && p.con.hasConnected);
|
||||||
playersToSend.selectFrom(tdata.players, p -> !p.isLocal() && p.con.hasConnected);
|
if(!playersToSend.isEmpty()){
|
||||||
if(!playersToSend.isEmpty()){
|
writeEntitySnapshotsTeam(team, playersToSend);
|
||||||
writeEntitySnapshotsTeam(playersToSend);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
//Serialize once for all players
|
|
||||||
writeEntitySnapshotsAll();
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
//Serialize for each player
|
//Serialize once for all players
|
||||||
Groups.player.each(p -> !p.isLocal() && p.con.hasConnected, player -> {
|
writeEntitySnapshotsAll();
|
||||||
try{
|
}
|
||||||
writeEntitySnapshot(player);
|
|
||||||
}catch(IOException e){
|
//write custom player-specific entities (usually labels)
|
||||||
Log.err(e);
|
for(Player player : Groups.player){
|
||||||
}
|
if(player.con != null && player.con.hasConnected && player.con.localEntities.size > 0){
|
||||||
});
|
writeCustomEntitySnapshot(player, player.con.localEntities);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package mindustry.entities.comp;
|
|||||||
import arc.util.io.*;
|
import arc.util.io.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
|
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
@@ -21,7 +22,7 @@ abstract class SyncComp implements Entityc{
|
|||||||
void afterSync(){}
|
void afterSync(){}
|
||||||
void interpolate(){}
|
void interpolate(){}
|
||||||
|
|
||||||
boolean isSyncHidden(Player player){
|
boolean isSyncHidden(Team team){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -213,9 +213,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Replace
|
@Replace
|
||||||
public boolean isSyncHidden(Player player){
|
public boolean isSyncHidden(Team team){
|
||||||
//shooting reveals position so bullets can be seen
|
//shooting reveals position so bullets can be seen
|
||||||
return !isShooting() && inFogTo(player.team());
|
return !isShooting() && inFogTo(team);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ import mindustry.ui.*;
|
|||||||
public abstract class WorldLabelComp implements Posc, Drawc, Syncc{
|
public abstract class WorldLabelComp implements Posc, Drawc, Syncc{
|
||||||
@Import int id;
|
@Import int id;
|
||||||
@Import float x, y;
|
@Import float x, y;
|
||||||
|
@Import boolean added;
|
||||||
|
|
||||||
public static final byte
|
public static final byte
|
||||||
flagBackground = 1,
|
flagBackground = 1 << 0,
|
||||||
flagOutline = 2,
|
flagOutline = 1 << 1,
|
||||||
flagAlignLeft = 4,
|
flagAlignLeft = 1 << 2,
|
||||||
flagAlignRight = 8,
|
flagAlignRight = 1 << 3,
|
||||||
flagAutoscale = 16,
|
flagAutoscale = 1 << 4;
|
||||||
flagOnlyParentVisible = 32;
|
|
||||||
|
|
||||||
public String text = "sample text";
|
public String text = "sample text";
|
||||||
public float fontSize = 1f, z = Layer.playerName + 1;
|
public float fontSize = 1f, z = Layer.playerName + 1;
|
||||||
@@ -37,6 +37,7 @@ public abstract class WorldLabelComp implements Posc, Drawc, Syncc{
|
|||||||
|
|
||||||
@Replace
|
@Replace
|
||||||
public float clipSize(){
|
public float clipSize(){
|
||||||
|
if(parent != null) return Float.MAX_VALUE;
|
||||||
return text.length() * 10f * fontSize;
|
return text.length() * 10f * fontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,9 +55,6 @@ public abstract class WorldLabelComp implements Posc, Drawc, Syncc{
|
|||||||
if(parent != null){
|
if(parent != null){
|
||||||
x += parent.x();
|
x += parent.x();
|
||||||
y += parent.y();
|
y += parent.y();
|
||||||
if((flags & flagOnlyParentVisible) != 0 && !parent.isLocal()){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
drawAt(text, x, y, z, flags, fontSize, Align.center, (flags & flagAlignLeft) != 0 ? Align.left : (flags & flagAlignRight) != 0 ? Align.right : Align.center);
|
drawAt(text, x, y, z, flags, fontSize, Align.center, (flags & flagAlignLeft) != 0 ? Align.left : (flags & flagAlignRight) != 0 ? Align.right : Align.center);
|
||||||
}
|
}
|
||||||
@@ -111,6 +109,21 @@ public abstract class WorldLabelComp implements Posc, Drawc, Syncc{
|
|||||||
Draw.z(z);
|
Draw.z(z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Makes this label visible only to the specific player. This must be called instead of add(). */
|
||||||
|
public void show(Player player){
|
||||||
|
if(added || player.con == null) return;
|
||||||
|
player.con.localEntities.add(this);
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Hides this player-specific label. If you used {@link #show(Player)} previously, you must call this method instead of {@link #hide()}! */
|
||||||
|
public void hide(Player player){
|
||||||
|
if(!added || player.con == null) return;
|
||||||
|
player.con.localEntities.remove(this);
|
||||||
|
Call.removeWorldLabel(player.con, id);
|
||||||
|
added = false;
|
||||||
|
}
|
||||||
|
|
||||||
/** This MUST be called instead of remove()! */
|
/** This MUST be called instead of remove()! */
|
||||||
public void hide(){
|
public void hide(){
|
||||||
remove();
|
remove();
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ public abstract class NetConnection{
|
|||||||
public Ratekeeper chatRate = new Ratekeeper();
|
public Ratekeeper chatRate = new Ratekeeper();
|
||||||
/** Handles packet spam rate limits. */
|
/** Handles packet spam rate limits. */
|
||||||
public Ratekeeper packetRate = new Ratekeeper();
|
public Ratekeeper packetRate = new Ratekeeper();
|
||||||
|
/** Entities that only this player will get synced to them. */
|
||||||
|
public Seq<Syncc> localEntities = new Seq<>(false);
|
||||||
|
|
||||||
//TODO: refactor to state enum
|
//TODO: refactor to state enum
|
||||||
public boolean hasConnected, hasBegunConnecting, determiningAssets, receivingAssets, hasDisconnected;
|
public boolean hasConnected, hasBegunConnecting, determiningAssets, receivingAssets, hasDisconnected;
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ public class Menus{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//internal use only
|
//internal use only
|
||||||
@Remote
|
@Remote(variants = Variant.both)
|
||||||
public static void removeWorldLabel(int id){
|
public static void removeWorldLabel(int id){
|
||||||
var label = Groups.label.getByID(id);
|
var label = Groups.label.getByID(id);
|
||||||
if(label != null){
|
if(label != null){
|
||||||
|
|||||||
Reference in New Issue
Block a user