Skip to content

Commit 583ff27

Browse files
committed
Added names
also fixed a bug where players were not rendered in the correct order.
1 parent 1b65c40 commit 583ff27

6 files changed

Lines changed: 205 additions & 9 deletions

File tree

FEZ.MultiplayerMod.mm/FEZ.MultiplayerMod.mm.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
<Compile Include="MultiplayerMod\MultiplayerClient.cs" />
7676
<Compile Include="MultiplayerMod\FezMultiplayerMod.cs" />
7777
<Compile Include="MultiplayerMod\MultiplayerClientSettings.cs" />
78+
<Compile Include="MultiplayerMod\TextDrawer3D.cs" />
7879
<Compile Include="Patches\Fez.cs" />
7980
</ItemGroup>
8081
<ItemGroup>

FEZ.MultiplayerMod.mm/MultiplayerMod/FezMultiplayerMod.cs

Lines changed: 119 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ protected override void Dispose(bool disposing)
119119
}
120120

121121
private readonly SpriteBatch drawer;
122+
private TextDrawer3D textDrawer;
122123
public override void Initialize()
123124
{
124125
DrawOrder = 9;//player gomez is at 9, bombs and trixel partical system and warp gates are at 10, black holes & liquids are at 50, split up cubes at 75, cloud shadows at 100
@@ -129,6 +130,8 @@ public override void Initialize()
129130
};
130131
ILightingPostProcess lpp = null;
131132
_ = Waiters.Wait(() => (lpp = ServiceHelper.Get<ILightingPostProcess>()) != null, () => lpp.DrawGeometryLights += PreDraw);
133+
textDrawer = new TextDrawer3D(this.Game, FontManager.Big);
134+
132135
DrawActionScheduler.Schedule(delegate
133136
{
134137
mesh.Effect = (effect = new GomezEffect());
@@ -197,7 +200,8 @@ public override void Draw(GameTime gameTime)
197200
drawer.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
198201
try
199202
{
200-
foreach (var p in mp.Players.Values)
203+
var players = mp.Players.Values.OrderByDescending(p => Vector3.Distance(mp.Players[mp.MyUuid].Position, p.Position));
204+
foreach (var p in players)
201205
{
202206
if (ShowDebugInfo)
203207
{
@@ -338,11 +342,11 @@ internal void DrawPlayer(MultiplayerClient.PlayerMetadata p, GameTime gameTime,
338342
if (doDraw) mesh.Draw();
339343
graphicsDevice.PrepareStencilWrite(StencilMask.None);
340344
#endregion
345+
341346
#region draw player name
342-
//Note: could move this to its own method if we ever want to draw the name of ourself on the screen
343-
//Note: sanitize player name because the game's font doesn't have every character; possibly limit it to only writable ASCII characters?
344-
//TODO draw the name to a Texture2D, assign the texture to a Mesh, and draw the Mesh; See SpeechBubble for inspiration
345-
//TODO alternatively we could simply draw the text on top of everything else using the same method as the debug text, but that'd look strange in first-person
347+
Vector3 namePos = p.Position + Vector3.Up;//TODO center text over mesh
348+
//TODO: sanitize player name because the game's font doesn't have every character; See CommonChars below
349+
textDrawer.DrawPlayerName(GraphicsDevice, p.PlayerName, namePos, CameraManager.Rotation, mesh.DepthWrites);
346350
#endregion
347351
}
348352
//Adapted from GomezHost.GetPositionOffset
@@ -357,5 +361,115 @@ private Vector3 GetPositionOffset(MultiplayerClient.PlayerMetadata p, ref Animat
357361
return vector + (vector2.X * view.RightVector() * p.LookingDirection.Sign() + vector2.Y * Vector3.UnitY);
358362
}
359363
#endregion
364+
365+
//
366+
//
367+
// For player names and whatnot
368+
// should be an inclusive list of all characters supported by all of the languages' game fonts
369+
// probably should restrict certain characters for internal use (like punctuation and symbols)
370+
// also need to figure out how to handle people using characters that are not in this list
371+
//
372+
// Complete list: (?<=")[A-Za-z0-9 !"#$%&'()*+,\-./:;<>=?@\[\]\\^_`{}|~]+(?=")
373+
//
374+
// Common punctuation characters: [ !"#$%&'()*+,\-./:;<>=?@\[\]^_`{}|~]
375+
// Potential reserved characters: [ #$&\\`]
376+
//
377+
public static readonly string[] CommonChars = new string[]{
378+
" ",
379+
"!",
380+
"\"",
381+
"#",
382+
"$",
383+
"%",
384+
"&",
385+
"'",
386+
"(",
387+
")",
388+
"*",
389+
"+",
390+
",",
391+
"-",
392+
".",
393+
"/",
394+
"0",
395+
"1",
396+
"2",
397+
"3",
398+
"4",
399+
"5",
400+
"6",
401+
"7",
402+
"8",
403+
"9",
404+
":",
405+
";",
406+
"<",
407+
"=",
408+
">",
409+
"?",
410+
"@",
411+
"A",
412+
"B",
413+
"C",
414+
"D",
415+
"E",
416+
"F",
417+
"G",
418+
"H",
419+
"I",
420+
"J",
421+
"K",
422+
"L",
423+
"M",
424+
"N",
425+
"O",
426+
"P",
427+
"Q",
428+
"R",
429+
"S",
430+
"T",
431+
"U",
432+
"V",
433+
"W",
434+
"X",
435+
"Y",
436+
"Z",
437+
"[",
438+
"\\",
439+
"]",
440+
"^",
441+
"_",
442+
"`",
443+
"a",
444+
"b",
445+
"c",
446+
"d",
447+
"e",
448+
"f",
449+
"g",
450+
"h",
451+
"i",
452+
"j",
453+
"k",
454+
"l",
455+
"m",
456+
"n",
457+
"o",
458+
"p",
459+
"q",
460+
"r",
461+
"s",
462+
"t",
463+
"u",
464+
"v",
465+
"w",
466+
"x",
467+
"y",
468+
"z",
469+
"{",
470+
"|",
471+
"}",
472+
"~"
473+
};
360474
}
361475
}

FEZ.MultiplayerMod.mm/MultiplayerMod/MultiplayerServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ internal MultiplayerServer(MultiplayerClientSettings settings)
144144
{
145145
//IPEndPoint object will allow us to read datagrams sent from any source.
146146
IPEndPoint t = new IPEndPoint(IPAddress.Any, listenPort);
147-
ProcessDatagram(udpListener.Receive(ref t), t);
147+
ProcessDatagram(udpListener.Receive(ref t), t);//Note: udpListener.Receive blocks until there is a datagram o read
148148
}
149149
udpListener.Close();
150150
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using FezEngine;
2+
using FezEngine.Components;
3+
using FezEngine.Effects;
4+
using FezEngine.Structure;
5+
using FezEngine.Tools;
6+
using Microsoft.Xna.Framework;
7+
using Microsoft.Xna.Framework.Graphics;
8+
using System;
9+
using System.Collections.Generic;
10+
11+
namespace FezGame.MultiplayerMod
12+
{
13+
public class TextDrawer3D
14+
{
15+
private readonly Dictionary<string, RenderTarget2D> textures;
16+
private readonly Mesh mesh = new Mesh()
17+
{
18+
AlwaysOnTop = true,
19+
SamplerState = SamplerState.PointClamp,
20+
Blending = BlendingMode.Alphablending
21+
};
22+
private readonly GlyphTextRenderer GTR;
23+
private readonly SpriteFont Font;
24+
private SpriteBatch spriteBatch;
25+
private Color TextColor = Color.White;
26+
public TextDrawer3D(Game Game, SpriteFont Font)
27+
{
28+
textures = new Dictionary<string, RenderTarget2D>();
29+
mesh.AddFace(new Vector3(1f), Vector3.Zero, FaceOrientation.Front, centeredOnOrigin: true, doublesided: true);
30+
GTR = new GlyphTextRenderer(Game);
31+
this.Font = Font;
32+
}
33+
//draws the name to a Texture2D, assign the texture to a Mesh, and draw the Mesh; See SpeechBubble for inspiration
34+
internal void DrawPlayerName(GraphicsDevice GraphicsDevice, string playerName, Vector3 position, Quaternion rotation, bool DepthDraw)
35+
{
36+
RenderTarget2D textTexture;
37+
if(!textures.TryGetValue(playerName, out textTexture)){
38+
mesh.Effect = new DefaultEffect.Textured();
39+
const float scale = 1f;
40+
Vector2 textSize = GTR.MeasureWithGlyphs(Font, playerName, scale, out bool multilineGlyphs);
41+
42+
Vector2 scalableMiddleSize = textSize + Vector2.One * 8f + Vector2.UnitX * 8f;
43+
44+
textTexture = new RenderTarget2D(GraphicsDevice, 2*(int)textSize.X, 2*(int)textSize.Y, mipMap: false, GraphicsDevice.PresentationParameters.BackBufferFormat, GraphicsDevice.PresentationParameters.DepthStencilFormat, 0, RenderTargetUsage.PreserveContents);
45+
46+
if (this.spriteBatch == null) {
47+
this.spriteBatch = new SpriteBatch(GraphicsDevice);
48+
}
49+
GraphicsDevice.SetRenderTarget(textTexture);
50+
GraphicsDevice.PrepareDraw();
51+
GraphicsDevice.Clear(ClearOptions.Target, ColorEx.TransparentWhite, 1f, 0);
52+
if (Culture.IsCJK)
53+
{
54+
spriteBatch.BeginLinear();
55+
}
56+
else
57+
{
58+
spriteBatch.BeginPoint();
59+
}
60+
Vector2 vector3 = (Culture.IsCJK ? new Vector2(8f) : Vector2.Zero);
61+
GTR.DrawString(spriteBatch, Font, playerName, (scalableMiddleSize / 2f - textSize / 2f + vector3).Round(), TextColor, scale);
62+
spriteBatch.End();
63+
GraphicsDevice.SetRenderTarget(null);
64+
mesh.Effect = new DefaultEffect.Textured();
65+
mesh.SamplerState = Culture.IsCJK ? SamplerState.AnisotropicClamp : SamplerState.PointClamp;
66+
mesh.Material.Opacity = 1;
67+
textures.Add(playerName, textTexture);
68+
}
69+
70+
mesh.Texture = textTexture;
71+
//mesh.FirstGroup.TextureMatrix.Set(new Matrix(1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 1f, 1f, 1f, 0f, 0f, 0f, 0f, 0f));
72+
mesh.Scale = new Vector3(1f);
73+
mesh.Rotation = rotation;
74+
mesh.Position = position;
75+
mesh.DepthWrites = DepthDraw;
76+
mesh.AlwaysOnTop = true;
77+
//TODO draw text background
78+
mesh.Draw();
79+
}
80+
}
81+
}

Notes_To_Do_list_for_FezMultiplayerMod.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
- [ ] Might be able to use name as unique identifiers instead of GUID; would require handshake
1515

16-
- [ ] display names above players heads
16+
- [x] display names above players heads
1717

1818
- [ ] add IP verifying and banning functionality; requires a handshake when the client connects to the server
1919

changelog.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ various bug fixes and improvements
1212
added server mode
1313
added settings file
1414

15-
0.0.3
15+
0.0.3 - 2024-01-07T07:34:56Z
1616
bug fixes
1717
refactoring
1818
added new optional dedicated server exe
1919
fix problems due to time differences
2020
implicitly assign port to endpoint if missing
2121
fixed KeyNotFoundException sometimes being thrown when iterating over Players.Values
22-
22+
Added player names
2323

2424

0 commit comments

Comments
 (0)