Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GM] Fixed wrong BasePlayer returned on NPC connection #378

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
42 changes: 42 additions & 0 deletions src/SampSharp.GameMode/Events/NPCConnectionEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SampSharp
// Copyright 2017 Tim Potze
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using SampSharp.GameMode.World;
using System;

namespace SampSharp.GameMode.Events
{
/// <summary>
/// Provides data for the <see cref="NPC"/>NPC connection event.
/// </summary>
public class NPCConnectionEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the NPCConnectionEventArgs class.
/// </summary>
/// <param name="npcBasePlayer"><see cref="BasePlayer"/> of the NPC.</param>
public NPCConnectionEventArgs(BasePlayer npcBasePlayer)
{
NPCBasePlayer = npcBasePlayer;
}

// Not using Player here as we don't delete the object when
// the player fails to connect to the server.

/// <summary>
/// Gets the NPC's <see cref="BasePlayer"/> trying to connect.
/// </summary>
public BasePlayer NPCBasePlayer { get; }
}
}
26 changes: 8 additions & 18 deletions src/SampSharp.GameMode/SAMP/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,34 +160,24 @@ public static void SendRconCommand(string command)
}

/// <summary>
/// Connect an NPC to the server.
/// Connects an NPC to the server.
/// </summary>
/// <param name="name">The name the NPC should connect as. Must follow the same rules as normal player names.</param>
/// <param name="script">The NPC script name that is located in the npcmodes folder (without the .amx extension).</param>
/// <returns>
/// An instance of <see cref="BasePlayer" /> based on the first available player slot. If no slots are available,
/// null.
/// An instance of <see cref="NPC" />
/// </returns>
public static BasePlayer ConnectNPC(string name, string script)
public static NPC ConnectNPC(string name, string script)
{
var id = -1;
var max = MaxPlayers;
if (BasePlayer.FindByName(name) != null)
throw new Exception($"The name \"{name}\" is already used in game");

for (var i = 0; i < max; i++)
if (!ServerInternal.Instance.IsPlayerConnected(i))
id = i;

if (id == -1)
return null;

ServerInternal.Instance.ConnectNPC(name, script);
var result = BasePlayer.FindOrCreate(id);
result.IsNpcOverride = true;
return result;
NPC npc = new NPC(name, script);
return npc;
}

/// <summary>
/// Set the world weather for all players.
/// Sets the world weather for all players.
/// </summary>
/// <param name="weatherid">The weather to set.</param>
public static void SetWeather(int weatherid)
Expand Down
20 changes: 20 additions & 0 deletions src/SampSharp.GameMode/World/BasePlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@ public partial class BasePlayer : IdentifiedPool<BasePlayer>, IWorldObject
/// Maximum length of the text in a chat bubble.
/// </summary>
public const int MaxChatBubbleLength = 144;

/// <summary>
/// Finds a <see cref="BasePlayer"/> from the given <paramref name="name"/>
/// </summary>
/// <param name="name">The name of the BasePlayer to find</param>
/// <returns>The found BasePlayer</returns>
public static BasePlayer FindByName(string name)
{
BasePlayer result = null;
for (int i = 0; i < Server.MaxPlayers; i++)
{
if (BasePlayer.Find(i) != null)
{
BasePlayer p = BasePlayer.Find(i);
if (p.Name.Equals(name))
result = p;
}
}
return result;
}

#region Constructors

Expand Down
75 changes: 75 additions & 0 deletions src/SampSharp.GameMode/World/NPC.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SampSharp
// Copyright 2017 Tim Potze
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using SampSharp.GameMode.Events;
using System;
using static SampSharp.GameMode.SAMP.Server;

namespace SampSharp.GameMode.World
{
/// <summary>
/// Represents a SA-MP NPC
/// </summary>
public class NPC
{
internal string Name { get; }

#region Constructors

/// <summary>
/// Initialize a new instance of the <see cref="NPC"/> class.
/// </summary>
/// <param name="name">The name the NPC should connect as. Must follow the same rules as normal player names.</param>
/// <param name="script">The NPC script name that is located in the npcmodes folder (without the .amx extension).</param>
public NPC(string name, string script)
{
this.Name = name;
BaseMode.Instance.PlayerConnected += (p, e) => this.OnNPCConnect(p as BasePlayer);
ServerInternal.Instance.ConnectNPC(name, script);
}
#endregion

#region Callbacks

private void OnNPCConnect(BasePlayer p)
{
if(p.Name.Equals(Name) && p.IsNPC)
{
PlayerInstance = p;
Connected?.Invoke(this, new NPCConnectionEventArgs(p));
}

}

#endregion

#region Properties

/// <summary>
/// The <see cref="BasePlayer"/> of the NPC
/// </summary>
public BasePlayer PlayerInstance { get; set; }

#endregion

#region Events

/// <summary>
/// Occurs when the NPC instance has been connected
/// </summary>
public event EventHandler<NPCConnectionEventArgs> Connected;

#endregion
}
}