Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
55cfc64
Fixes for Player list ping updates:
RedFlames Apr 17, 2022
b2e9467
Change 'Spoofed' placeholder to '???ms' on invalid ping data.
RedFlames Apr 17, 2022
9404249
Use an expression-body property for Settings.PlayerListAllowSplit lik…
RedFlames Apr 19, 2022
3f10a19
Fix ghost life cycle edge cases
May 24, 2022
b04ac86
Check for (BlurRT != null) in CelesteNetRenderHelperComponent.cs
RedFlames Jun 7, 2022
ea9d15d
This List?.First(...) should've been a FirstOrDefault() since it shou…
RedFlames Jun 7, 2022
8adda05
Replace the Fonts.Load() with a Fonts.Get() in CelesteNetClientFontMo…
RedFlames Jun 7, 2022
924fe3a
Didn't realize one call to Load will be needed. No idea why I thought…
RedFlames Jun 7, 2022
b458760
Fix non-interactive players always responding with 'release me' packe…
RedFlames Jun 10, 2022
f80b8f0
Fix GravityHelper issue
Jun 28, 2022
7e6b740
Prevent chat from opening if keyboard is used for text entry dialogs,…
RedFlames Aug 26, 2022
26c344c
TODO: not detecting end of EH cutscene properly yet.
RedFlames Aug 29, 2022
d2a8096
Introduced Delay before removing EmptySpaceHeart from TimeRateSkip si…
RedFlames Sep 4, 2022
abeaaf5
Prevent chat component NREs when Client is null
RedFlames Sep 15, 2022
6867414
Resend graphics when hair length change detected, and stop hair sim o…
RedFlames Sep 22, 2022
aef046e
Remove hair debug stuff
RedFlames Sep 22, 2022
cf7a07c
Merge branch 'pingfix-playerlist' into oct-2022-integration-test
RedFlames Sep 30, 2022
77e65f2
Merge remote-tracking branch 'upstream/ghost-fixes' into oct-2022-int…
RedFlames Sep 30, 2022
3eda670
PR #29 suggested fixes
RedFlames Sep 30, 2022
8dc98d6
Merge branch 'misc-rendering-fixes' into oct-2022-integration-test
RedFlames Sep 30, 2022
78bc531
Merge branch 'grab-release-fix' into oct-2022-integration-test
RedFlames Sep 30, 2022
f1008ef
Merge branch 'ui-keyboard-entry-chat-bugfix' into oct-2022-integratio…
RedFlames Sep 30, 2022
7409754
Merge branch 'emote-timeskip-fixes' into oct-2022-integration-test
RedFlames Sep 30, 2022
e42244d
Merge branch 'chat-component-client-null' into oct-2022-integration-test
RedFlames Sep 30, 2022
d98ae3c
Merge branch 'hair-length-fix' into oct-2022-integration-test
RedFlames Sep 30, 2022
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
6 changes: 4 additions & 2 deletions CelesteNet.Client/CelesteNetClientFontMono.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ namespace Celeste.Mod.CelesteNet.Client {
// Copy of ActiveFont that always uses a font with monospace Latin characters / Arabic numbers.
public static class CelesteNetClientFontMono {

// English is always loaded. Other language fonts must be loaded manually. Load only loads once.
public static PixelFont Font => Fonts.Load(Dialog.Languages["japanese"].FontFace);
private static string FontFace => Dialog.Languages["japanese"].FontFace;

// English is always loaded. Other language fonts must be loaded manually. Only load once.
public static PixelFont Font => Fonts.Get(FontFace) ?? Fonts.Load(FontFace);

public static PixelFontSize FontSize => Font.Get(BaseSize);

Expand Down
13 changes: 12 additions & 1 deletion CelesteNet.Client/Components/CelesteNetChatComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ public void Send(string text) {
}

public void Handle(CelesteNetConnection con, DataChat msg) {
if (Client == null)
return;

lock (Log) {
if (msg.Player?.ID == Client.PlayerInfo?.ID) {
foreach (DataChat pending in Pending.Values) {
Expand Down Expand Up @@ -177,12 +180,20 @@ public void Handle(CelesteNetConnection con, DataChat msg) {
public override void Update(GameTime gameTime) {
base.Update(gameTime);

if (Client == null) {
Active = false;
return;
}

_Time += Engine.RawDeltaTime;
_TimeSinceCursorMove += Engine.RawDeltaTime;

Overworld overworld = Engine.Scene as Overworld;
bool isRebinding = Engine.Scene == null ||
Engine.Scene.Entities.FindFirst<KeyboardConfigUI>() != null ||
Engine.Scene.Entities.FindFirst<ButtonConfigUI>() != null;
Engine.Scene.Entities.FindFirst<ButtonConfigUI>() != null ||
((overworld?.Current ?? overworld?.Next) is OuiFileNaming naming && naming.UseKeyboardInput) ||
((overworld?.Current ?? overworld?.Next) is UI.OuiModOptionString stringInput && stringInput.UseKeyboardInput);

if (!(Engine.Scene?.Paused ?? true) || isRebinding) {
string typing = Typing;
Expand Down
7 changes: 5 additions & 2 deletions CelesteNet.Client/Components/CelesteNetEmoteComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ public override void Update(GameTime gameTime) {
if (Wheel == null)
level.Add(Wheel = new(Player));

if (!level.Paused && Settings.EmoteWheel && !Player.Dead) {
// TimeRate check is for Prologue Dash prompt freeze
if (!level.Paused && Settings.EmoteWheel && !Player.Dead && Engine.TimeRate > 0.05f) {
Wheel.Shown = CelesteNetClientModule.Instance.JoystickEmoteWheel.Value.LengthSquared() >= 0.36f;
int selected = Wheel.Selected;
if (Wheel.Shown && selected != -1 && CelesteNetClientModule.Instance.ButtonEmoteSend.Pressed) {
Expand Down Expand Up @@ -148,7 +149,9 @@ public override void Update(GameTime gameTime) {

private void OnHeartGemCollect(On.Celeste.HeartGem.orig_Collect orig, HeartGem self, Player player) {
orig(self, player);
Wheel?.TimeRateSkip.Add("HeartGem");
Wheel?.TimeRateSkip.Add(self.IsFake ? "EmptySpaceHeart" : "HeartGem");
if (self.IsFake && Wheel != null)
Wheel.timeSkipForcedDelay = 10f;
}

private void OnHeartGemEndCutscene(On.Celeste.HeartGem.orig_EndCutscene orig, HeartGem self) {
Expand Down
116 changes: 60 additions & 56 deletions CelesteNet.Client/Components/CelesteNetMainComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class CelesteNetMainComponent : CelesteNetGameComponent {
private AreaKey? MapEditorArea;
private bool WasIdle;
private bool WasInteractive;
private int SentHairLength = 0;

public HashSet<string> ForceIdle = new();
public bool StateUpdated;
Expand Down Expand Up @@ -128,15 +129,7 @@ protected override void Dispose(bool disposing) {
}

public void Cleanup() {
Player = null;
PlayerBody = null;
Session = null;
WasIdle = false;
WasInteractive = false;

foreach (Ghost ghost in Ghosts.Values)
ghost?.RemoveSelf();
Ghosts.Clear();
ResetState();

if (IsGrabbed && Player.StateMachine.State == Player.StFrozen)
Player.StateMachine.State = Player.StNormal;
Expand Down Expand Up @@ -168,8 +161,7 @@ public void Handle(CelesteNetConnection con, DataPlayerInfo player) {
return;

if (string.IsNullOrEmpty(player.DisplayName)) {
ghost.RunOnUpdate(ghost => ghost.NameTag.Name = "");
Ghosts.TryRemove(player.ID, out _);
RemoveGhost(player);
LastFrames.TryRemove(player.ID, out _);
Client.Data.FreeOrder<DataPlayerFrame>(player.ID);
return;
Expand All @@ -193,13 +185,9 @@ public void Handle(CelesteNetConnection con, DataChannelMove move) {
}

} else {
if (!Ghosts.TryGetValue(move.Player.ID, out Ghost ghost) ||
ghost == null)
if (!RemoveGhost(move.Player))
return;

ghost.RunOnUpdate(ghost => ghost.NameTag.Name = "");
Ghosts.TryRemove(move.Player.ID, out _);

foreach (DataType data in Client.Data.GetBoundRefs(move.Player))
if (data.TryGet(Client.Data, out MetaPlayerPrivateState state))
Client.Data.FreeBoundRef(data);
Expand All @@ -219,10 +207,12 @@ public void Handle(CelesteNetConnection con, DataPlayerState state) {
ghost == null)
return;

if (Settings.Interactions != state.Interactive && ghost == GrabbedBy)
SendReleaseMe();

Session session = Session;
if (session != null && (state.SID != session.Area.SID || state.Mode != session.Area.Mode || state.Level == LevelDebugMap)) {
ghost.RunOnUpdate(ghost => ghost.NameTag.Name = "");
Ghosts.TryRemove(id, out _);
RemoveGhost(state.Player); // If we get here, id must belong to a valid ghost, so it can't be uint.MaxValue and state.Player mustn't be null
return;
}

Expand Down Expand Up @@ -278,7 +268,7 @@ public void Handle(CelesteNetConnection con, DataPlayerFrame frame) {
UpdateIdleTag(ghost, ref ghost.IdleTag, state.Idle);
ghost.UpdateGeneric(frame.Position, frame.Scale, frame.Color, frame.Facing, frame.Speed);
ghost.UpdateAnimation(frame.CurrentAnimationID, frame.CurrentAnimationFrame);
ghost.UpdateHair(frame.Facing, frame.HairColors, frame.HairTexture0, frame.HairSimulateMotion);
ghost.UpdateHair(frame.Facing, frame.HairColors, frame.HairTexture0, frame.HairSimulateMotion && !state.Idle);
ghost.UpdateDash(frame.DashWasB, frame.DashDir); // TODO: Get rid of this, sync particles separately!
ghost.UpdateDead(frame.Dead && state.Level == session.Level);
ghost.UpdateFollowers((Settings.Entities & CelesteNetClientSettings.SyncMode.Receive) == 0 ? Dummy<DataPlayerFrame.Entity>.EmptyArray : frame.Followers);
Expand Down Expand Up @@ -447,9 +437,12 @@ public void Handle(CelesteNetConnection con, DataMoveTo target) {

public void Handle(CelesteNetConnection con, DataPlayerGrabPlayer grab) {
Player player = Player;
if (Engine.Scene is not Level level || level.Paused || player == null || !Settings.Interactions)
if (player != null && !Settings.Interactions && (grab.Player.ID == Client.PlayerInfo.ID || grab.Grabbing.ID == Client.PlayerInfo.ID))
goto Release;

if (Engine.Scene is not Level level || level.Paused || player == null || !Settings.Interactions)
return;

if (grab.Player.ID != Client.PlayerInfo.ID && grab.Grabbing.ID == Client.PlayerInfo.ID) {
if (GrabCooldown > 0f) {
GrabCooldown = GrabCooldownMax;
Expand Down Expand Up @@ -589,17 +582,19 @@ protected Ghost CreateGhost(Level level, DataPlayerInfo player, DataPlayerGraphi
UnsupportedSpriteModes.Add(graphics.SpriteMode);
RunOnMainThread(() => {
level.Add(ghost);
level.OnEndOfFrame += () => ghost.Active = true;
//level.OnEndOfFrame += () => ghost.Active = true;
ghost.UpdateGraphics(graphics);
});
ghost.UpdateGraphics(graphics);
}
return ghost;
}

protected void RemoveGhost(DataPlayerInfo info) {
Ghosts.TryRemove(info.ID, out Ghost ghost);
protected bool RemoveGhost(DataPlayerInfo player) {
if (!Ghosts.TryRemove(player.ID, out Ghost ghost))
return false;
ghost?.RunOnUpdate(g => g.NameTag.Name = "");
return true;
}

public void UpdateIdleTag(Entity target, ref GhostEmote idleTag, bool idle) {
Expand Down Expand Up @@ -670,30 +665,27 @@ public override void Update(GameTime gameTime) {
GrabbedBy = null;

if (ready && Engine.Scene is MapEditor) {
Player = null;
PlayerBody = null;
Session = null;
WasIdle = false;
WasInteractive = false;
ResetState();
AreaKey area = (AreaKey) f_MapEditor_area.GetValue(null);

if (MapEditorArea == null || MapEditorArea.Value.SID != area.SID || MapEditorArea.Value.Mode != area.Mode) {
MapEditorArea = area;
// FIXME: NOTE BEFORE MERGING: can we move the ResetState() call here, which would be more inline with the below if?
SendState();
}
}

if (Player != null && MapEditorArea == null) {
Player = null;
PlayerBody = null;
Session = null;
WasIdle = false;
WasInteractive = false;
ResetState();
SendState();
}
return;
}

foreach (Ghost g in Ghosts.Values)
if (g != null)
g.Active = true;

bool grabReleased = false;
grabReleased |= IsGrabbed && (GrabTimeout += Engine.RawDeltaTime) >= GrabTimeoutMax;
grabReleased |= GrabbedBy != null && GrabbedBy.Scene != level;
Expand Down Expand Up @@ -725,17 +717,17 @@ public override void Update(GameTime gameTime) {
}

if (Player == null || Player.Scene != level) {
Player = level.Tracker.GetEntity<Player>();
if (Player != null) {
PlayerBody = Player;
Session = level.Session;
WasIdle = false;
WasInteractive = false;
Player player = level.Tracker.GetEntity<Player>();
if (player != null) {
ResetState(player, level.Session);
StateUpdated |= true;
SendGraphics();
}
}

if (Player != null && Player.Sprite != null && SentHairLength != Player.Sprite.HairCount)
SendGraphics();

bool idle = level.FrozenOrPaused || level.Overlay != null;
if (WasIdle != idle) {
WasIdle = idle;
Expand Down Expand Up @@ -797,17 +789,14 @@ public void OnSetActualDepth(On.Monocle.Scene.orig_SetActualDepth orig, Scene sc
public void OnLoadLevel(On.Celeste.Level.orig_LoadLevel orig, Level level, Player.IntroTypes playerIntro, bool isFromLoader = false) {
orig(level, playerIntro, isFromLoader);

Session = level.Session;
WasIdle = false;
WasInteractive = false;

if (Client == null)
return;
Player player = null;
if (Client != null)
player = level.Tracker.GetEntity<Player>();

Player = level.Tracker.GetEntity<Player>();
PlayerBody = Player;
ResetState(player, level.Session);

SendState();
if (Client != null)
SendState();
}

public void OnExitLevel(Level level, LevelExit exit, LevelExit.Mode mode, Session session, HiresSnow snow) {
Expand All @@ -832,17 +821,15 @@ private Player OnLoadNewPlayer(On.Celeste.Level.orig_LoadNewPlayer orig, Vector2
private void OnPlayerAdded(On.Celeste.Player.orig_Added orig, Player self, Scene scene) {
orig(self, scene);

Session = (scene as Level)?.Session;
WasIdle = false;
WasInteractive = false;
Player = self;
PlayerBody = self;

ResetState(self, (scene as Level)?.Session);
SendState();
SendGraphics();

foreach (DataPlayerFrame frame in LastFrames.Values.ToArray())
Handle(null, frame);
// We can't directly handle the frames here, as then ghost creation logic could fail if we're currently loading a level in OnEndOfFrame
scene.OnEndOfFrame += () => {
foreach (DataPlayerFrame frame in LastFrames.Values.ToArray())
Handle(null, frame);
};
}

private PlayerDeadBody OnPlayerDie(On.Celeste.Player.orig_Die orig, Player self, Vector2 direction, bool evenIfInvincible, bool registerDeathInStats) {
Expand Down Expand Up @@ -908,6 +895,22 @@ private void ILTransitionRoutine(ILContext il) {

#endregion

public void ResetState(Player player = null, Session ses = null) {
// Clear ghosts if the scene changed
if (player != null && player.Scene != Player?.Scene) {
lock (Ghosts) {
foreach (Ghost ghost in Ghosts.Values)
ghost?.RemoveSelf();
Ghosts.Clear();
}
}

Player = player;
PlayerBody = player;
Session = ses;
WasIdle = false;
WasInteractive = false;
}

#region Send

Expand Down Expand Up @@ -966,6 +969,7 @@ public void SendGraphics() {
HairScales = hairScales,
HairTextures = hairTextures
});
SentHairLength = hairCount;
} catch (Exception e) {
Logger.Log(LogLevel.INF, "client-main", $"Error in SendGraphics:\n{e}");
Context.DisposeSafe();
Expand Down
Loading