0.4.0: Mitspieler in der Welt, BSO-Konto (Spiel-Ticket)

- Mitspieler als Bus/Spielfigur mit Namensschild, weich bewegt (RemotePlayers, Models)
- Ohne gueltiges Spiel-Ticket vom Launcher kein Multiplayer; Name kommt aus dem Konto
- Protokoll 2 (Hello mit Ticket), IPv6-Adressen
- Nach Szenenwechsel erst nach 3 s neu anlegen (Absturz im Test 0.3.0)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-28 18:10:48 +01:00
co-authored by Claude Opus 5.5
parent 35f2d1330d
commit 51c1ebc938
12 changed files with 397 additions and 10 deletions
+40
View File
@@ -37,6 +37,15 @@ namespace BSO
static delegate* unmanaged<nint> getTimer;
static delegate* unmanaged<nint, float> getTime;
// Mitspieler in der Welt (RemotePlayers) - optional: fehlt etwas, laeuft der Rest trotzdem
static nint game; // Vision::Game (VisGame_cl)
static delegate* unmanaged<nint, byte*, float*, byte*, byte*, nint> createEntity;
static delegate* unmanaged<nint, float, float, float, void> setPosition;
static delegate* unmanaged<nint, float, float, float, void> setOrientation;
static delegate* unmanaged<nint, void> removeEntity;
static delegate* unmanaged<nint, byte*, float*, short, int> drawMessage3D;
public static bool CanSpawn { get; private set; }
public static bool Init()
{
if (tried) return Loaded;
@@ -58,10 +67,41 @@ namespace BSO
Loaded = message != 0 && camera != 0 && entityTable != 0 && print != null && getMainCamera != null && getPosition != null
&& getOrientation != null && getTimer != null && getTime != null;
game = Export(module, "?Game@Vision@@2VVisGame_cl@@A");
// VisBaseEntity_cl* VisGame_cl::CreateEntity(const char* klasse, const VisVector_cl& pos, const char* modell, const char* parameter)
createEntity = (delegate* unmanaged<nint, byte*, float*, byte*, byte*, nint>)Export(module, "?CreateEntity@VisGame_cl@@QEAAPEAVVisBaseEntity_cl@@PEBDAEBVVisVector_cl@@00@Z");
setPosition = (delegate* unmanaged<nint, float, float, float, void>)Export(module, "?SetPosition@VisObject3D_cl@@QEAAXMMM@Z");
setOrientation = (delegate* unmanaged<nint, float, float, float, void>)Export(module, "?SetOrientation@VisObject3D_cl@@QEAAXMMM@Z");
removeEntity = (delegate* unmanaged<nint, void>)Export(module, "?Remove@VisBaseEntity_cl@@QEAAXXZ");
// int VisGame_cl::DrawMessage3D(const char* text, const VisVector_cl& pos, short) - wie Print nur fuer dieses Bild
drawMessage3D = (delegate* unmanaged<nint, byte*, float*, short, int>)Export(module, "?DrawMessage3D@VisGame_cl@@QEAAHPEBDAEBVVisVector_cl@@F@Z");
CanSpawn = game != 0 && createEntity != null && setPosition != null && setOrientation != null && removeEntity != null && drawMessage3D != null;
Bootstrap.Log(Loaded ? "Vision Engine gefunden, alle Funktionen da" : "Vision Engine: Funktionen fehlen");
return Loaded;
}
/// <summary>Neue Entity mit Modell (nur Grafik, keine Physik). 0 = fehlgeschlagen.</summary>
public static nint CreateEntity(string className, Vec3 pos, string modelFile)
{
float* v = stackalloc float[4] { pos.X, pos.Y, pos.Z, 0 }; // VisVector_cl (3 float, Platz fuer Ausrichtung)
byte[] cls = ToAscii(className), model = ToAscii(modelFile);
byte* none = stackalloc byte[1] { 0 };
fixed (byte* c = cls, m = model) return createEntity(game, c, v, m, none);
}
public static void SetPosition(nint obj, Vec3 p) => setPosition(obj, p.X, p.Y, p.Z);
public static void SetOrientation(nint obj, Vec3 yawPitchRoll) => setOrientation(obj, yawPitchRoll.X, yawPitchRoll.Y, yawPitchRoll.Z);
/// <summary>Entity zum Entfernen vormerken (die Engine raeumt sie am Ende des Bildes weg).</summary>
public static void RemoveEntity(nint entity) => removeEntity(entity);
/// <summary>Text an einer Stelle in der Welt, fuer dieses Bild (Namensschild). text mit ToAscii vorbereitet.</summary>
public static void DrawText3D(byte[] text, Vec3 pos)
{
float* v = stackalloc float[4] { pos.X, pos.Y, pos.Z, 0 };
fixed (byte* t = text) drawMessage3D(game, t, v, 0);
}
static nint Export(nint module, string name)
{
if (NativeLibrary.TryGetExport(module, name, out nint address)) return address;