Add SendCustomEventQueued()
This commit is contained in:
@ -267,10 +267,19 @@ namespace RageCoop.Client
|
||||
{
|
||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
||||
packet.Unpack(data);
|
||||
Main.Logger.Debug(packet.Args.DumpWithType());
|
||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||
}
|
||||
break;
|
||||
case PacketType.CustomEventQueued:
|
||||
{
|
||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
packet.Unpack(data);
|
||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case PacketType.FileTransferChunk:
|
||||
{
|
||||
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
|
||||
|
@ -19,7 +19,6 @@ namespace RageCoop.Client.Scripting
|
||||
API.RegisterCustomEventHandler(CustomEvents.DeleteServerProp, DeleteServerProp);
|
||||
API.RegisterCustomEventHandler(CustomEvents.DeleteEntity, DeleteEntity);
|
||||
API.RegisterCustomEventHandler(CustomEvents.SetDisplayNameTag, SetNameTag);
|
||||
API.RegisterCustomEventHandler(CustomEvents.SetEntity, SetEntity);
|
||||
API.RegisterCustomEventHandler(CustomEvents.ServerBlipSync, ServerBlipSync);
|
||||
API.RegisterCustomEventHandler(CustomEvents.DeleteServerBlip, DeleteServerBlip);
|
||||
API.RegisterCustomEventHandler(CustomEvents.CreateVehicle, CreateVehicle);
|
||||
@ -30,41 +29,35 @@ namespace RageCoop.Client.Scripting
|
||||
|
||||
private void UpdatePedBlip(CustomEventReceivedArgs e)
|
||||
{
|
||||
API.QueueAction(() =>
|
||||
var p = Ped.FromHandle((int)e.Args[0]);
|
||||
if (p == null) { return; }
|
||||
if (p.Handle==Game.Player.Character.Handle)
|
||||
{
|
||||
var p = Ped.FromHandle((int)e.Args[0]);
|
||||
if(p == null) { return; }
|
||||
if (p.Handle==Game.Player.Character.Handle)
|
||||
{
|
||||
API.Config.BlipColor=(BlipColor)(byte)e.Args[1];
|
||||
API.Config.BlipSprite=(BlipSprite)(ushort)e.Args[2];
|
||||
API.Config.BlipScale=(float)e.Args[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
var b = p.AttachedBlip;
|
||||
if(b == null) { b=p.AddBlip(); }
|
||||
b.Color=(BlipColor)(byte)e.Args[1];
|
||||
b.Sprite=(BlipSprite)(ushort)e.Args[2];
|
||||
b.Scale=(float)e.Args[3];
|
||||
}
|
||||
});
|
||||
API.Config.BlipColor=(BlipColor)(byte)e.Args[1];
|
||||
API.Config.BlipSprite=(BlipSprite)(ushort)e.Args[2];
|
||||
API.Config.BlipScale=(float)e.Args[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
var b = p.AttachedBlip;
|
||||
if (b == null) { b=p.AddBlip(); }
|
||||
b.Color=(BlipColor)(byte)e.Args[1];
|
||||
b.Sprite=(BlipSprite)(ushort)e.Args[2];
|
||||
b.Scale=(float)e.Args[3];
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateVehicle(CustomEventReceivedArgs e)
|
||||
{
|
||||
API.QueueAction(() =>
|
||||
var veh = World.CreateVehicle((Model)e.Args[1], (Vector3)e.Args[2], (float)e.Args[3]);
|
||||
veh.CanPretendOccupants=false;
|
||||
var v = new SyncedVehicle()
|
||||
{
|
||||
var veh = World.CreateVehicle((Model)e.Args[1],(Vector3)e.Args[2],(float)e.Args[3]);
|
||||
veh.CanPretendOccupants=false;
|
||||
var v = new SyncedVehicle()
|
||||
{
|
||||
ID=(int)e.Args[0],
|
||||
MainVehicle=veh,
|
||||
OwnerID=Main.LocalPlayerID,
|
||||
};
|
||||
EntityPool.Add(v);
|
||||
});
|
||||
ID=(int)e.Args[0],
|
||||
MainVehicle=veh,
|
||||
OwnerID=Main.LocalPlayerID,
|
||||
};
|
||||
EntityPool.Add(v);
|
||||
}
|
||||
|
||||
private void DeleteServerBlip(CustomEventReceivedArgs e)
|
||||
@ -72,9 +65,7 @@ namespace RageCoop.Client.Scripting
|
||||
if (EntityPool.ServerBlips.TryGetValue((int)e.Args[0], out var blip))
|
||||
{
|
||||
EntityPool.ServerBlips.Remove((int)e.Args[0]);
|
||||
API.QueueAction(()=>{
|
||||
blip?.Delete();
|
||||
});
|
||||
blip?.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,35 +79,22 @@ namespace RageCoop.Client.Scripting
|
||||
int rot= (int)obj.Args[5];
|
||||
var name=(string)obj.Args[6];
|
||||
Blip blip;
|
||||
API.QueueAction(() =>
|
||||
if (!EntityPool.ServerBlips.TryGetValue(id, out blip))
|
||||
{
|
||||
// Main.Logger.Debug($"{sprite},{color},{scale},{pos},{rot}");
|
||||
if (!EntityPool.ServerBlips.TryGetValue(id, out blip))
|
||||
{
|
||||
EntityPool.ServerBlips.Add(id, blip=World.CreateBlip(pos));
|
||||
}
|
||||
blip.Sprite = sprite;
|
||||
blip.Color = color;
|
||||
blip.Scale = scale;
|
||||
blip.Position = pos;
|
||||
blip.Rotation = rot;
|
||||
blip.Name = name;
|
||||
});
|
||||
EntityPool.ServerBlips.Add(id, blip=World.CreateBlip(pos));
|
||||
}
|
||||
blip.Sprite = sprite;
|
||||
blip.Color = color;
|
||||
blip.Scale = scale;
|
||||
blip.Position = pos;
|
||||
blip.Rotation = rot;
|
||||
blip.Name = name;
|
||||
}
|
||||
|
||||
private void SetEntity(CustomEventReceivedArgs obj)
|
||||
{
|
||||
API.QueueAction(() =>
|
||||
{
|
||||
var e=Entity.FromHandle((int)obj.Args[0]);
|
||||
e.Position = (Vector3)obj.Args[1];
|
||||
e.Rotation = (Vector3)obj.Args[2];
|
||||
});
|
||||
}
|
||||
|
||||
private void DeleteEntity(CustomEventReceivedArgs e)
|
||||
{
|
||||
API.QueueAction(() => Entity.FromHandle((int)e.Args[0])?.Delete());
|
||||
Entity.FromHandle((int)e.Args[0])?.Delete();
|
||||
}
|
||||
|
||||
public override void OnStop()
|
||||
@ -140,8 +118,9 @@ namespace RageCoop.Client.Scripting
|
||||
if (EntityPool.ServerProps.TryGetValue(id, out var prop))
|
||||
{
|
||||
EntityPool.ServerProps.Remove(id);
|
||||
API.QueueAction(() => { prop?.MainProp?.Delete(); });
|
||||
prop?.MainProp?.Delete();
|
||||
}
|
||||
|
||||
}
|
||||
private void ServerObjectSync(CustomEventReceivedArgs e)
|
||||
{
|
||||
@ -158,7 +137,7 @@ namespace RageCoop.Client.Scripting
|
||||
prop.ModelHash= (Model)e.Args[1];
|
||||
prop.Position=(Vector3)e.Args[2];
|
||||
prop.Rotation=(Vector3)e.Args[3];
|
||||
Main.QueueAction(() => { prop.Update(); });
|
||||
prop.Update();
|
||||
}
|
||||
private void NativeCall(CustomEventReceivedArgs e)
|
||||
{
|
||||
@ -172,79 +151,76 @@ namespace RageCoop.Client.Scripting
|
||||
{
|
||||
arguments.Add(GetInputArgument(e.Args[i]));
|
||||
}
|
||||
Main.QueueAction(() =>
|
||||
|
||||
if (returnType==TypeCode.Empty)
|
||||
{
|
||||
|
||||
if (returnType==TypeCode.Empty)
|
||||
{
|
||||
Function.Call(hash, arguments.ToArray());
|
||||
return;
|
||||
}
|
||||
var t = returnType;
|
||||
int id = (int)e.Args[1];
|
||||
Function.Call(hash, arguments.ToArray());
|
||||
return;
|
||||
}
|
||||
var t = returnType;
|
||||
int id = (int)e.Args[1];
|
||||
|
||||
|
||||
switch (returnType)
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<bool>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Byte:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<byte>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<char>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
switch (returnType)
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<bool>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Byte:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<byte>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<char>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Single:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<float>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Single:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<float>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Double:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<double>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Double:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<double>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Int16:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<short>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<short>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Int32:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<int>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<int>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Int64:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<long>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<long>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.String:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<string>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.String:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<string>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.UInt16:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<ushort>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<ushort>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.UInt32:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<uint>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<uint>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.UInt64:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<ulong>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
}
|
||||
});
|
||||
case TypeCode.UInt64:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new List<object> { id, Function.Call<ulong>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
private InputArgument GetInputArgument(object obj)
|
||||
|
@ -9,10 +9,12 @@ namespace RageCoop.Core
|
||||
|
||||
internal class CustomEvent : Packet
|
||||
{
|
||||
public CustomEvent(Func<byte,BitReader,object> onResolve = null)
|
||||
public CustomEvent(Func<byte,BitReader,object> onResolve = null,bool queued=false)
|
||||
{
|
||||
_resolve= onResolve;
|
||||
_queued= queued;
|
||||
}
|
||||
private bool _queued;
|
||||
private Func<byte, BitReader, object> _resolve { get; set; }
|
||||
public int Hash { get; set; }
|
||||
public bool IsStaged { get; set; }=false;
|
||||
@ -21,7 +23,7 @@ namespace RageCoop.Core
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
Args= Args ?? new object[] { };
|
||||
message.Write((byte)PacketType.CustomEvent);
|
||||
message.Write(_queued ? (byte)PacketType.CustomEventQueued: (byte)PacketType.CustomEvent);
|
||||
|
||||
List<byte> result = new List<byte>();
|
||||
result.AddInt(Hash);
|
||||
|
@ -31,6 +31,7 @@ namespace RageCoop.Core
|
||||
AllResourcesSent=15,
|
||||
|
||||
CustomEvent = 16,
|
||||
CustomEventQueued = 17,
|
||||
#region Sync
|
||||
|
||||
#region INTERVAL
|
||||
|
@ -159,7 +159,7 @@ namespace RageCoop.Server
|
||||
var argsList= new List<object>(args);
|
||||
argsList.InsertRange(0, new object[] { (byte)Type.GetTypeCode(typeof(T)), RequestNativeCallID<T>(callBack), (ulong)hash });
|
||||
|
||||
SendCustomEvent(CustomEvents.NativeCall, argsList.ToArray());
|
||||
SendCustomEventQueued(CustomEvents.NativeCall, argsList.ToArray());
|
||||
}
|
||||
/// <summary>
|
||||
/// Send a native call to client and ignore it's response.
|
||||
@ -171,7 +171,7 @@ namespace RageCoop.Server
|
||||
var argsList = new List<object>(args);
|
||||
argsList.InsertRange(0, new object[] { (byte)TypeCode.Empty,(ulong)hash });
|
||||
// Server.Logger?.Debug(argsList.DumpWithType());
|
||||
SendCustomEvent(CustomEvents.NativeCall, argsList.ToArray());
|
||||
SendCustomEventQueued(CustomEvents.NativeCall, argsList.ToArray());
|
||||
}
|
||||
private int RequestNativeCallID<T>(Action<object> callback)
|
||||
{
|
||||
@ -222,6 +222,36 @@ namespace RageCoop.Server
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a CustomEvent that'll be queued at client side and invoked from script thread
|
||||
/// </summary>
|
||||
/// <param name="hash"></param>
|
||||
/// <param name="args"></param>
|
||||
public void SendCustomEventQueued(int hash, params object[] args)
|
||||
{
|
||||
if (!IsReady)
|
||||
{
|
||||
Server.Logger?.Warning($"Player \"{Username}\" is not ready!");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||
new Packets.CustomEvent(null,true)
|
||||
{
|
||||
Hash=hash,
|
||||
Args=args
|
||||
}.Pack(outgoingMessage);
|
||||
Server.MainNetServer.SendMessage(outgoingMessage, Connection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Event);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Server.Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ namespace RageCoop.Server.Scripting
|
||||
{
|
||||
var argsList = new List<object>(args);
|
||||
argsList.InsertRange(0, new object[] { (byte)TypeCode.Empty, (ulong)hash });
|
||||
SendCustomEvent(clients, CustomEvents.NativeCall, argsList.ToArray());
|
||||
SendCustomEventQueued(clients, CustomEvents.NativeCall, argsList.ToArray());
|
||||
}
|
||||
|
||||
|
||||
@ -280,6 +280,27 @@ namespace RageCoop.Server.Scripting
|
||||
Server.Send(p, c, ConnectionChannel.Event, NetDeliveryMethod.ReliableOrdered);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a CustomEvent that'll be queued at client side and invoked from script thread
|
||||
/// </summary>
|
||||
/// <param name="targets"></param>
|
||||
/// <param name="eventHash"></param>
|
||||
/// <param name="args"></param>
|
||||
public void SendCustomEventQueued(List<Client> targets, int eventHash, params object[] args)
|
||||
{
|
||||
|
||||
targets ??= new(Server.Clients.Values);
|
||||
var p = new Packets.CustomEvent(null,true)
|
||||
{
|
||||
Args=args,
|
||||
Hash=eventHash
|
||||
};
|
||||
foreach (var c in targets)
|
||||
{
|
||||
Server.Send(p, c, ConnectionChannel.Event, NetDeliveryMethod.ReliableOrdered);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Register an handler to the specifed event hash, one event can have multiple handlers.
|
||||
/// </summary>
|
||||
|
@ -41,14 +41,14 @@ namespace RageCoop.Server.Scripting
|
||||
{
|
||||
foreach(var obj in objects)
|
||||
{
|
||||
API.SendCustomEvent(clients, CustomEvents.ServerPropSync,obj.ID, obj.Model ,obj.Position,obj.Rotation );
|
||||
API.SendCustomEventQueued(clients, CustomEvents.ServerPropSync,obj.ID, obj.Model ,obj.Position,obj.Rotation );
|
||||
}
|
||||
}
|
||||
public void SendServerBlipsTo(List<ServerBlip> objects, List<Client> clients = null)
|
||||
{
|
||||
foreach (var obj in objects)
|
||||
{
|
||||
API.SendCustomEvent(clients, CustomEvents.ServerBlipSync, obj.ID, (ushort)obj.Sprite, (byte)obj.Color, obj.Scale,obj.Position,obj.Rotation,obj.Name );
|
||||
API.SendCustomEventQueued(clients, CustomEvents.ServerBlipSync, obj.ID, (ushort)obj.Sprite, (byte)obj.Color, obj.Scale,obj.Position,obj.Rotation,obj.Name );
|
||||
}
|
||||
}
|
||||
void NativeResponse(CustomEventReceivedArgs e)
|
||||
|
@ -135,7 +135,7 @@ namespace RageCoop.Server
|
||||
Model=model,
|
||||
_pos= pos,
|
||||
};
|
||||
owner.SendCustomEvent(CustomEvents.CreateVehicle,veh.ID, model, pos, heading);
|
||||
owner.SendCustomEventQueued(CustomEvents.CreateVehicle,veh.ID, model, pos, heading);
|
||||
Vehicles.Add(veh.ID, veh);
|
||||
return veh;
|
||||
}
|
||||
|
@ -89,16 +89,14 @@ namespace RageCoop.Server
|
||||
/// <summary>
|
||||
/// Send updated information to clients, would be called automatically.
|
||||
/// </summary>
|
||||
internal virtual void Update() {
|
||||
Owner?.SendCustomEvent(CustomEvents.SetEntity, Handle, Position, Rotation);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Delete this object
|
||||
/// </summary>
|
||||
public virtual void Delete()
|
||||
{
|
||||
Owner?.SendCustomEvent(CustomEvents.DeleteEntity, Handle);
|
||||
Owner?.SendCustomEventQueued(CustomEvents.DeleteEntity, Handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -131,7 +129,7 @@ namespace RageCoop.Server
|
||||
/// </summary>
|
||||
public override void Delete()
|
||||
{
|
||||
Server.API.SendCustomEvent(null,CustomEvents.DeleteServerProp,ID);
|
||||
Server.API.SendCustomEventQueued(null,CustomEvents.DeleteServerProp,ID);
|
||||
Server.API.Entities.RemoveProp(ID);
|
||||
}
|
||||
|
||||
@ -157,7 +155,7 @@ namespace RageCoop.Server
|
||||
/// <summary>
|
||||
/// Send updated information to clients, would be called automatically.
|
||||
/// </summary>
|
||||
internal override void Update()
|
||||
internal void Update()
|
||||
{
|
||||
Server.API.Server.BaseScript.SendServerPropsTo(new() { this });
|
||||
}
|
||||
@ -315,7 +313,7 @@ namespace RageCoop.Server
|
||||
/// </summary>
|
||||
public void Delete()
|
||||
{
|
||||
Server.API.SendCustomEvent(null, CustomEvents.DeleteServerBlip,ID);
|
||||
Server.API.SendCustomEventQueued(null, CustomEvents.DeleteServerBlip,ID);
|
||||
Server.Entities.RemoveServerBlip(ID);
|
||||
}
|
||||
|
||||
@ -406,7 +404,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
private void DoUpdate()
|
||||
{
|
||||
Ped.Owner.SendCustomEvent(CustomEvents.UpdatePedBlip,Ped.Handle,(byte)Color,(ushort)Sprite,Scale);
|
||||
Ped.Owner.SendCustomEventQueued(CustomEvents.UpdatePedBlip,Ped.Handle,(byte)Color,(ushort)Sprite,Scale);
|
||||
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user