roflmuffin / CounterStrikeSharp

CounterStrikeSharp allows you to write server plugins in C# for Counter-Strike 2/Source2/CS2
https://docs.cssharp.dev
Other
743 stars 111 forks source link

EventPlayerDeath breaks the server #387

Closed AdMinesss closed 4 months ago

AdMinesss commented 5 months ago

The server crashes if I try to get an Attacker or Assister in the EventPlayerDeath event if the player becomes an observer. Maybe I should have added a check, but I expected the answer to be false or something like that Error: "ART<2><[U:1:847461507]>" ChangeTeam() CTMDBG , team 3, req team 1 willSwitch 0, 22.67 ClientPutInServer create new player controller [Kev] "Kev<3>" ChangeTeam() CTMDBG , team 0, req team 3 willSwitch 0, 22.67 Unhandled exception. System.InvalidOperationException: The type 'System.UInt32&' of property 'Ping' on type 'CounterStrikeSharp.API.Core.CCSPlayerController' is invalid for serialization or deserialization because it is a pointer type, is a ref struct, or contains generic parameters that have not been replaced by specific types. at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_CannotSerializeInvalidType(Type typeToConvert, Type declaringType, MemberInfo memberInfo) at System.Text.Json.Serialization.Metadata.ReflectionJsonTypeInfo1.CreateProperty(Type typeToConvert, MemberInfo memberInfo, JsonSerializerOptions options, Boolean shouldCheckForRequiredKeyword) at System.Text.Json.Serialization.Metadata.ReflectionJsonTypeInfo1.LateAddProperties() at System.Text.Json.Serialization.Metadata.JsonTypeInfo.InitializePropertyCache() at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure() at System.Text.Json.Serialization.Metadata.JsonTypeInfo.gConfigureLocked|143_0() at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable) at System.Text.Json.Serialization.JsonConverter.ResolvePolymorphicConverter(Object value, JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.Converters.DictionaryOfTKeyTValueConverter3.OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonDictionaryConverter3.OnTryWrite(Utf8JsonWriter writer, TDictionary dictionary, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter1.TryWriteAsObject(Utf8JsonWriter writer, Object value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.Converters.DictionaryOfTKeyTValueConverter3.OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonDictionaryConverter3.OnTryWrite(Utf8JsonWriter writer, TDictionary dictionary, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.JsonSerializer.WriteCore[TValue](Utf8JsonWriter writer, TValue& value, JsonTypeInfo1 jsonTypeInfo) at System.Text.Json.JsonSerializer.WriteString[TValue](TValue& value, JsonTypeInfo1 jsonTypeInfo) at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options) at GameStatIntegration.<>c__DisplayClass31_2.<b4>d.MoveNext() --- End of stack trace from previous location --- at System.Threading.Tasks.Task.<>c.b__128_1(Object state) at System.Threading.QueueUserWorkItemCallback.Execute() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart() ./game/cs2.sh: line 118: 43 Aborted (core dumped) ${STEAM_RUNTIME_PREFIX} ${GAME_DEBUGGER} "${GAMEROOT}"/${GAMEEXE} "$@" container@pterodactyl~ Server marked as offline...

roflmuffin commented 5 months ago

Is this in a pre or post hook? Could you provide a basic reproduction example?

github-actions[bot] commented 5 months ago

This issue has been marked needs-author-action and may be missing some important information.

AdMinesss commented 4 months ago

Is this in a pre or post hook? Could you provide a basic reproduction example?

omitting some code details, here is an example If you need the full code, let me know and I'll send it to you.


public override void Load(bool hotReload)
    {
        base.Load(hotReload);
        RegisterEventHandler<EventPlayerDeath>((@event, info) =>
        {
            Server.NextFrame(async () =>
                {
                    Dictionary<string, object>          event_body   = new Dictionary<string, object>();
                    Dictionary<string, object>          send_data   = new Dictionary<string, object>();
                    event_body = new Dictionary<string, object>
                    {
                        { "Assister",           @event.Assister},      
                        { "Assistedflash",      @event.Assistedflash},    
                        { "attacker",           @event.Attacker},  
                        { "Attackerblind",      @event.Attackerblind},
                    };
                    send_data.Add("event",     event_body);
                    _= client.SendMessage(JsonSerializer.Serialize(send_data));
                });
            return HookResult.Continue;
        });
    }
roflmuffin commented 4 months ago

The values in the @event are not available in the next frame, because the event is disposed on the server. The workaround for this is to capture the variables outside of next frame and then use them inside the hook. I.e. build your dictionary in the synchronous code and then fire it from the Async next frame. Let me know if this requires clarification

AdMinesss commented 4 months ago

I realized my mistake Thank you very much :)