These are chat archives for ikkentim/SampSharp

18th
Aug 2015
Florian van Dillen
@fvandillen
Aug 18 2015 13:53
Oh hi, don't mind my inactivity :D
PlayerConnected?.Invoke(player, e); I guess this is 6.0 syntax?
Does it mean IF IsThisTheCase THEN .DoStuff?
Tim Potze
@ikkentim
Aug 18 2015 14:01
Welcome back :)
Let me show you what it compiles to...
This is in basemode:
        protected virtual void OnPlayerEditGlobalObject(BasePlayer player, EditGlobalObjectEventArgs e)
        {
            EventHandler<EditGlobalObjectEventArgs> expr_07 = this.PlayerEditGlobalObject;
            if (expr_07 != null)
            {
                expr_07(player, e);
            }
        }
Florian van Dillen
@fvandillen
Aug 18 2015 14:04
So it's not really a syntax but rather a type of eventhandler?
Tim Potze
@ikkentim
Aug 18 2015 14:04
Not really it has nothing to do with event handlers.. : (typing...)
A?.B is if A is not null, then A.B otherwise null
Florian van Dillen
@fvandillen
Aug 18 2015 14:05
That's exactly what I need in a lot of cases
Tim Potze
@ikkentim
Aug 18 2015 14:05
A?.B?.C is if A is null, null, if A.B is null null, else A.B.C
Florian van Dillen
@fvandillen
Aug 18 2015 14:05
Creates some really clean syntax
Tim Potze
@ikkentim
Aug 18 2015 14:06
Indeed
Florian van Dillen
@fvandillen
Aug 18 2015 14:06
Also, custom events
Tim Potze
@ikkentim
Aug 18 2015 14:06
?
Florian van Dillen
@fvandillen
Aug 18 2015 14:07
(typing..)
Let's say I'd like to do stuff when a player registers
In a certain controller, I'd like to subscribe to OnPlayerRegister, much like I already do for other events from SampSharp
In the login controller, how do I "throw" the event so it can be handled by a different controller?
Crappy explanation, I know :smile:
Tim Potze
@ikkentim
Aug 18 2015 14:09
That's still a painful point I haven't got my head around properly... but you could use services
Services can be accessed anywhere you have access to the game mode
Oh also $"{VarOne} and {VarTwo}" compiles to string.Format("{0} {1}", VarOne, VarTwo)... here's a video on c# 6 https://channel9.msdn.com/Events/Visual-Studio/Connect-event-2014/116
but yeah I'd like to have something better to fire events around the game mode. Maybe services are the solution, maybe not
Florian van Dillen
@fvandillen
Aug 18 2015 14:12
Well how does it work in SampSharp itself?
Tim Potze
@ikkentim
Aug 18 2015 14:12
Services?
Florian van Dillen
@fvandillen
Aug 18 2015 14:12
I mean the library thows events, and I can catch them in controllers
Tim Potze
@ikkentim
Aug 18 2015 14:13
OnPlayerRegister you mean?
Florian van Dillen
@fvandillen
Aug 18 2015 14:13
Well lets take OnPlayerConnect
The SampSharp library causes that event
I can simply make a controller and choose how and where to handle that event
Tim Potze
@ikkentim
Aug 18 2015 14:14
In the controller you can simply register to gameMode.PlayerConnect += (sender, args) => { / ... /}
Florian van Dillen
@fvandillen
Aug 18 2015 14:14
Yes, that's how I am currently handling events
Tim Potze
@ikkentim
Aug 18 2015 14:14
or gameMode.PlayerConnect += someMethod;
Florian van Dillen
@fvandillen
Aug 18 2015 14:15
But there's stuff that happens in my gamemode that should be handled in the same way
Take an anti cheat module
Tim Potze
@ikkentim
Aug 18 2015 14:15
So you want to intercept the event before further calling?
Or..?
Florian van Dillen
@fvandillen
Aug 18 2015 14:16
When it finds someone cheating, it should fire something like OnPlayerCheatDetected
I then want to register that event to a method which resides in a controller
Tim Potze
@ikkentim
Aug 18 2015 14:16
Ah that way. Do you know how services work?
Florian van Dillen
@fvandillen
Aug 18 2015 14:16
Nope, that's why I asked haha
Tim Potze
@ikkentim
Aug 18 2015 14:16
okay, let my type for a while :P
Florian van Dillen
@fvandillen
Aug 18 2015 14:16
lol sure
thanks for your patience
Tim Potze
@ikkentim
Aug 18 2015 14:27
You can create a service as follows:
public interface IAntiCheatService : IService
{
  // It is good practice to create an interface for every service
  event EventHandler<PlayerEventArgs> PlayerCheatDetected;
}

public class AntiCheatService : IAntiCheatService
{
  public AntiCheatService(BaseMode gameMode)
  {
    if(gameMode == null) throw new ArgumentNullException(nameof(gameMode));
    GameMode = gameMode;
  }

  public BaseMode GameMode { get; } // I know... type is BaseMode, I want to fix that soon.

  // If you detect cheats from your AntiCheatController, you need to keep this public so you can call it from there. otherwise make it protected
  public void OnPlayerCheatDetected(PlayerEventArgs e)
  {
    PlayerCheatDetected?.(this, e);
  }
}

public class AntiCheatController : /* ... */, IGameServiceProvider
{
    private AntiCheatService _antiCheatService;
    // ...

      public virtual void RegisterServices(BaseMode gameMode, GameModeServiceContainer serviceContainer)
        {
            serviceContainer.AddService<IAntiCheatService>(_antiCheatService = new AntiCheatService(gameMode));
        }

    void Somewhere()
    {
       _antiCheatService.OnPlayerCheatDetected(new PlayerEventArgs(somePlayer));
    }
}

public class SomeOtherControllerOrWhereEver
{
    void Somewhere()
    {
        var antiCheatService = GameMode.Services.GetService<IAntiCheatService>();

        antiCheatService.PlayerCheatDetected += (sender, args) => { args.Player.SendClientMessage("That's sad :("); };
    }
}
Boom
As long as you have a reference to the game mode you can get a service of any given type.
Use of service interfaces is useful so you can swap the service out for another one with different functionality.
The framework contains one service in v0.7, BaseVehicleFactory.
This service is registered in BaseVehicleController. This service is used when you call BaseVehicle.Create.
This is very useful when you store additional data with vehicles or want to store any created vehicle in the database. You simply have to create a new service which implements IBaseVehicleFactory, and overwrite RegisterServices in BaseVehicleController.