using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using Microsoft.ClearScript.V8;
using GTA;
using GTA.Native;
using GTA.Math;
namespace CoopClient
{
///
/// Don't use this!
///
public class JavascriptHook : Script
{
private static readonly List _scriptEngines = new List();
internal static bool JavascriptLoaded { get; private set; } = false;
///
/// Don't use this!
///
public JavascriptHook()
{
Tick += Ontick;
}
private void Ontick(object sender, EventArgs e)
{
if (!Main.MainNetworking.IsOnServer() || _scriptEngines.Count == 0)
{
return;
}
lock (_scriptEngines)
{
_scriptEngines.ForEach(engine => engine.Script.API.InvokeTick());
}
}
internal static void LoadAll()
{
string serverAddress = Main.MainSettings.LastServerAddress.Replace(":", ".");
if (!Directory.Exists("scripts\\resources\\" + serverAddress))
{
try
{
Directory.CreateDirectory("scripts\\resources\\" + serverAddress);
}
catch (Exception ex)
{
GTA.UI.Notification.Show("~r~~h~Javascript Error");
Logger.Write(ex.Message, Logger.LogLevel.Server);
// Without the directory we can't do the other stuff
return;
}
}
lock (_scriptEngines)
{
foreach (string script in Directory.GetFiles("scripts\\resources\\" + serverAddress, "*.js"))
{
V8ScriptEngine engine = new V8ScriptEngine()
{
AccessContext = typeof(ScriptContext)
};
engine.AddHostObject("API", new ScriptContext());
engine.AddHostType(typeof(Dictionary<,>));
// SHVDN
engine.AddHostType(typeof(Vector3));
engine.AddHostType(typeof(Quaternion));
try
{
engine.Execute(File.ReadAllText(script));
}
catch (Exception ex)
{
GTA.UI.Notification.Show("~r~~h~Javascript Error");
Logger.Write(ex.Message, Logger.LogLevel.Server);
}
finally
{
engine.Script.API.InvokeStart();
_scriptEngines.Add(engine);
}
}
}
JavascriptLoaded = true;
}
internal static void StopAll()
{
lock (_scriptEngines)
{
_scriptEngines.ForEach(engine =>
{
engine.Script.API.InvokeStop();
engine.Dispose();
});
_scriptEngines.Clear();
}
JavascriptLoaded = false;
}
internal static void InvokePlayerConnect(string username, long nethandle)
{
lock (_scriptEngines)
{
_scriptEngines.ForEach(engine => engine.Script.API.InvokePlayerConnect(username, nethandle));
}
}
internal static void InvokePlayerDisonnect(string username, long nethandle, string reason = null)
{
lock (_scriptEngines)
{
_scriptEngines.ForEach(engine => engine.Script.API.InvokePlayerDisonnect(username, nethandle, reason));
}
}
internal static void InvokeChatMessage(string from, string message)
{
lock (_scriptEngines)
{
_scriptEngines.ForEach(engine => engine.Script.API.InvokeChatMessage(from, message));
}
}
}
internal class ScriptContext
{
#region DELEGATES
public delegate void EmptyEvent();
public delegate void PlayerConnectEvent(string username, long nethandle, string reason);
public delegate void ChatMessageEvent(string from, string message);
#endregion
#region EVENTS
public event EmptyEvent OnStart, OnStop, OnTick;
public event PlayerConnectEvent OnPlayerConnect, OnPlayerDisconnect;
public event ChatMessageEvent OnChatMessage;
internal void InvokeStart()
{
OnStart?.Invoke();
}
internal void InvokeStop()
{
OnStop?.Invoke();
}
internal void InvokeTick()
{
OnTick?.Invoke();
}
internal void InvokePlayerConnect(string username, long nethandle)
{
OnPlayerConnect?.Invoke(username, nethandle, null);
}
internal void InvokePlayerDisonnect(string username, long nethandle, string reason)
{
OnPlayerDisconnect?.Invoke(username, nethandle, reason);
}
internal void InvokeChatMessage(string from, string message)
{
OnChatMessage?.Invoke(from, message);
}
#endregion
/* ===== PLAYER STUFF ===== */
public void SendLocalMessage(string message)
{
Main.MainChat.AddMessage("JAVASCRIPT", message);
}
public string GetLocalUsername()
{
return Main.MainSettings.Username;
}
public long GetLocalNetHandle()
{
return Main.LocalNetHandle;
}
// This only applies to server-side created objects
public void CleanUpWorld()
{
Main.CleanUpWorld();
}
// This create an object to delete it with CleanUpWorld() or on disconnect
public void CreateObject(string hash, params object[] args)
{
if (!Hash.TryParse(hash, out Hash ourHash) || !Main.CheckNativeHash.ContainsKey((ulong)ourHash))
{
GTA.UI.Notification.Show("~r~~h~Javascript Error");
Logger.Write($"Hash \"{ourHash}\" has not been found!", Logger.LogLevel.Server);
return;
}
int result = Function.Call(ourHash, args.Select(o => new InputArgument(o)).ToArray());
foreach (KeyValuePair checkHash in Main.CheckNativeHash)
{
if (checkHash.Key == (ulong)ourHash)
{
lock (Main.ServerItems)
{
Main.ServerItems.Add(result, checkHash.Value);
}
break;
}
}
}
public void SendNotification(string message)
{
GTA.UI.Notification.Show(message);
}
public void SendNotification(string[] messages)
{
SendNotification(string.Concat(messages));
}
public bool IsPlayerInvincible()
{
return Game.Player.Character.IsInvincible;
}
public void SetPlayerInvincible(bool invincible)
{
Game.Player.Character.IsInvincible = invincible;
}
public Vector3 GetPlayerPosition()
{
return Game.Player.Character.Position;
}
public Vector3 GetPlayerRotation()
{
return Game.Player.Character.Rotation;
}
public void SetPlayerPosition(Vector3 position)
{
Game.Player.Character.Position = position;
}
public void SetPlayerPositionNoOffset(Vector3 position)
{
Game.Player.Character.PositionNoOffset = position;
}
public void SetPlayerRotation(Vector3 rotation)
{
Game.Player.Character.Rotation = rotation;
}
public bool IsPlayerInAnyVehicle()
{
return Game.Player.Character.IsInVehicle();
}
public int GetCharachterHandle()
{
return Game.Player.Character?.Handle ?? 0;
}
public Vector3? GetVehiclePosition()
{
return Game.Player.Character.CurrentVehicle?.Position;
}
public Vector3? GetVehicleRotation()
{
return Game.Player.Character.CurrentVehicle?.Rotation;
}
public void SetVehiclePosition(Vector3 position)
{
if (Game.Player.Character.IsInVehicle())
{
Game.Player.Character.CurrentVehicle.Position = position;
}
}
public void SetVehiclePositionNoOffset(Vector3 position)
{
if (Game.Player.Character.IsInVehicle())
{
Game.Player.Character.CurrentVehicle.PositionNoOffset = position;
}
}
public void SetVehicleRotation(Vector3 rotation)
{
if (Game.Player.Character.IsInVehicle())
{
Game.Player.Character.CurrentVehicle.Rotation = rotation;
}
}
public int GetVehicleHandle()
{
return Game.Player.Character?.CurrentVehicle?.Handle ?? 0;
}
public int GetVehicleSeatIndex()
{
return Game.Player.Character?.CurrentVehicle != null ? (int)Game.Player.Character?.SeatIndex : 0;
}
public void SetVehicleEngineStatus(bool turnedOn)
{
if (Game.Player.Character.IsInVehicle())
{
Game.Player.Character.CurrentVehicle.IsEngineRunning = turnedOn;
}
}
public bool GetVehicleEngineStatus()
{
return Game.Player.Character.IsInVehicle() ? Game.Player.Character.CurrentVehicle.IsEngineRunning : false;
}
public void RepairVehicle()
{
if (Game.Player.Character.IsInVehicle())
{
Game.Player.Character.CurrentVehicle.Repair();
}
}
public void GivePlayerWeapon(uint hash, int ammoCount, bool equipNow, bool isAmmoLoaded)
{
Game.Player.Character.Weapons.Give((WeaponHash)hash, ammoCount, equipNow, isAmmoLoaded);
}
public void SetPlayerHealth(int health)
{
Game.Player.Character.Health = health;
}
public void SetPlayerHealth(float health)
{
Game.Player.Character.HealthFloat = health;
}
public void SetPlayerArmor(int armor)
{
Game.Player.Character.Armor = armor;
}
public void SetPlayerArmor(float armor)
{
Game.Player.Character.ArmorFloat = armor;
}
/* ===== OTHER PLAYER STUFF ===== */
public Vector3 GetPlayerPosition(long nethandle)
{
lock (Main.Players)
{
return Main.Players.ContainsKey(nethandle) ? Main.Players.First(x => x.Key == nethandle).Value.Position : default;
}
}
public Vector3 GetPlayerRotation(long nethandle)
{
lock (Main.Players)
{
return Main.Players.ContainsKey(nethandle) ? Main.Players.First(x => x.Key == nethandle).Value.Rotation : default;
}
}
// Get nethandle and charachter handle
public Dictionary GetAllNearbyPlayers(float distance)
{
Dictionary result = new Dictionary();
lock (Main.Players)
{
Vector3 localPosition = Game.Player.Character.Position;
foreach (KeyValuePair player in Main.Players)
{
if (player.Value.Position.DistanceTo2D(localPosition) < distance)
{
// Character handle = 0 (if no character exists)
result.Add(player.Key, player.Value.Character?.Handle ?? 0);
}
}
}
return result;
}
public long GetNetHandleByUsername(string username)
{
lock (Main.Players)
{
return Main.Players.FirstOrDefault(x => x.Value.Username == username).Key;
}
}
/* ===== OTHER STUFF ===== */
public bool IsControlJustReleased(int control)
{
return Game.IsControlJustReleased((Control)control);
}
public bool IsControlJustPressed(int control)
{
return Game.IsControlJustPressed((Control)control);
}
public bool IsControlPressed(int control)
{
return Game.IsControlPressed((Control)control);
}
public void TriggerServerEvent(string eventName, params object[] args)
{
// TODO
}
}
}