feat: version 2.1.0

This commit is contained in:
AURUMVORXX
2025-04-22 17:26:54 +03:00
parent decd60070c
commit 2a0dc6245f
6 changed files with 448 additions and 417 deletions

View File

@@ -10,14 +10,15 @@ pip install git+https://github.com/AURUMVORXX/PyG2O.git
``` ```
3. Launch websocket client in your Squirrel scripts 3. Launch websocket client in your Squirrel scripts
``` ```
// PyG2O_Start(url, reconnect, silent) // PyG2O(url, silent, max_reconnect_attempts)
// reconnect - auto reconnect if server stopped
// silent - disable information prints // silent - disable information prints
// max_reconnect_attempts - maximum reconnect attempts if server will stop the connection (0 - infinite attempts). This value doesn't reset on connection
// Start server before any events // Start server
PyG2O_Start("ws://localhost:8080", true, false) local srv = PyG2O("ws://localhost:8080", true, 15)
srv.start()
addEventHandler("onInit"... // Stop server
srv.stop()
``` ```
4. In your application, launch asyncio event loop and websocket server 4. In your application, launch asyncio event loop and websocket server
```python ```python

View File

@@ -3,614 +3,571 @@ addEventHandler("onPlayerUseCheat", function(playerid, type)
{ {
local data = { local data = {
event = "onPlayerUseCheat", event = "onPlayerUseCheat",
args = { playerid = playerid,
playerid = playerid, type = type
type = type
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onBan", function(banInfo) addEventHandler("onBan", function(banInfo)
{ {
local data = { local data = {
event = "onBan", event = "onBan",
args = { ban = {
ban = { mac = "mac" in banInfo ? banInfo["mac"] : "-1",
mac = "mac" in banInfo ? banInfo["mac"] : "-1", ip = "ip" in banInfo ? banInfo["ip"] : "-1",
ip = "ip" in banInfo ? banInfo["ip"] : "-1", serial = "serial" in banInfo ? banInfo["serial"] : "-1",
serial = "serial" in banInfo ? banInfo["serial"] : "-1", name = "name" in banInfo ? banInfo["name"] : "-1",
name = "name" in banInfo ? banInfo["name"] : "-1", timestamp = "timestamp" in banInfo ? banInfo["timestamp"] : -1
timestamp = "timestamp" in banInfo ? banInfo["timestamp"] : -1
}
} }
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onExit", function() addEventHandler("onExit", function()
{ {
local data = { local data = {
event = "onExit", event = "onExit"
args = {}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onTick", function() addEventHandler("onTick", function()
{ {
local data = { local data = {
event = "onTick", event = "onTick"
args = {}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onTime", function(day, hour, min) addEventHandler("onTime", function(day, hour, min)
{ {
local data = { local data = {
event = "onTime", event = "onTime",
args = { day = day,
day = day, hour = hour,
hour = hour, min = min
min = min,
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onUnban", function(banInfo) addEventHandler("onUnban", function(banInfo)
{ {
local data = { local data = {
event = "onUnban", event = "onUnban",
args = { ban = {
ban = { mac = "mac" in banInfo ? banInfo["mac"] : "-1",
mac = "mac" in banInfo ? banInfo["mac"] : "-1", ip = "ip" in banInfo ? banInfo["ip"] : "-1",
ip = "ip" in banInfo ? banInfo["ip"] : "-1", serial = "serial" in banInfo ? banInfo["serial"] : "-1",
serial = "serial" in banInfo ? banInfo["serial"] : "-1", name = "name" in banInfo ? banInfo["name"] : "-1",
name = "name" in banInfo ? banInfo["name"] : "-1", timestamp = "timestamp" in banInfo ? banInfo["timestamp"] : -1
timestamp = "timestamp" in banInfo ? banInfo["timestamp"] : -1
}
} }
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onNpcActionFinished", function(npc_id, action_type, action_id, result) addEventHandler("onNpcActionFinished", function(npc_id, action_type, action_id, result)
{ {
local data = { local data = {
event = "onNpcActionFinished", event = "onNpcActionFinished",
args = { npc_id = npc_id,
npc_id = npc_id, action_type = action_type,
action_type = action_type, action_id = action_id,
action_id = action_id, result = result
result = result
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onNpcActionSent", function(npc_id, action_type, action_id) addEventHandler("onNpcActionSent", function(npc_id, action_type, action_id)
{ {
local data = { local data = {
event = "onNpcActionSent", event = "onNpcActionSent",
args = { npc_id = npc_id,
npc_id = npc_id, action_type = action_type,
action_type = action_type, action_id = action_id,
action_id = action_id,
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onNpcChangeHostPlayer", function(npc_id, current_id, previous_id) addEventHandler("onNpcChangeHostPlayer", function(npc_id, current_id, previous_id)
{ {
local data = { local data = {
event = "onNpcChangeHostPlayer", event = "onNpcChangeHostPlayer",
args = { npc_id = npc_id,
npc_id = npc_id, current_id = current_id,
current_id = current_id, previous_id = previous_id
previous_id = previous_id
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onNpcCreated", function(npc_id) addEventHandler("onNpcCreated", function(npc_id)
{ {
local data = { local data = {
event = "onNpcCreated", event = "onNpcCreated",
args = { npc_id = npc_id
npc_id = npc_id
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onNpcDestroyed", function(npc_id) addEventHandler("onNpcDestroyed", function(npc_id)
{ {
local data = { local data = {
event = "onNpcDestroyed", event = "onNpcCreated",
args = { npc_id = npc_id
npc_id = npc_id
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerChangeColor", function(playerid, r, g, b) addEventHandler("onPlayerChangeColor", function(playerid, r, g, b)
{ {
local data = { local data = {
event = "onPlayerChangeColor", event = "onPlayerChangeColor",
args = { playerid = playerid,
playerid = playerid, r = r,
r = r, g = g,
g = g, b = b
b = b
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerChangeFocus", function(playerid, oldFocusId, newFocusId) addEventHandler("onPlayerChangeFocus", function(playerid, oldFocusId, newFocusId)
{ {
local data = { local data = {
event = "onPlayerChangeFocus", event = "onPlayerChangeFocus",
args = { playerid = playerid,
playerid = playerid, oldFocusId = oldFocusId,
oldFocusId = oldFocusId, newFocusId = newFocusId
newFocusId = newFocusId
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerChangeHealth", function(playerid, previous, current) addEventHandler("onPlayerChangeHealth", function(playerid, previous, current)
{ {
local data = { local data = {
event = "onPlayerChangeHealth", event = "onPlayerChangeHealth",
args = { playerid = playerid,
playerid = playerid, previous = previous,
previous = previous, current = current
current = current
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerChangeMana", function(playerid, previous, current) addEventHandler("onPlayerChangeMana", function(playerid, previous, current)
{ {
local data = { local data = {
event = "onPlayerChangeMana", event = "onPlayerChangeMana",
args = { playerid = playerid,
playerid = playerid, previous = previous,
previous = previous, current = current
current = current
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerChangeMaxHealth", function(playerid, previous, current) addEventHandler("onPlayerChangeMaxHealth", function(playerid, previous, current)
{ {
local data = { local data = {
event = "onPlayerChangeMaxHealth", event = "onPlayerChangeMaxHealth",
args = { playerid = playerid,
playerid = playerid, previous = previous,
previous = previous, current = current
current = current
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerChangeMaxMana", function(playerid, previous, current) addEventHandler("onPlayerChangeMaxMana", function(playerid, previous, current)
{ {
local data = { local data = {
event = "onPlayerChangeMaxMana", event = "onPlayerChangeMaxMana",
args = { playerid = playerid,
playerid = playerid, previous = previous,
previous = previous, current = current
current = current
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerChangeWeaponMode", function(playerid, previous, current) addEventHandler("onPlayerChangeWeaponMode", function(playerid, previous, current)
{ {
local data = { local data = {
event = "onPlayerChangeWeaponMode", event = "onPlayerChangeWeaponMode",
args = { playerid = playerid,
playerid = playerid, previous = previous,
previous = previous, current = current
current = current
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerChangeWorld", function(playerid, previous, current) addEventHandler("onPlayerChangeWorld", function(playerid, previous, current)
{ {
local data = { local data = {
event = "onPlayerChangeWorld", event = "onPlayerChangeWorld",
args = { playerid = playerid,
playerid = playerid, previous = previous,
previous = previous, current = current
current = current
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerCommand", function(playerid, command, params) addEventHandler("onPlayerCommand", function(playerid, command, params)
{ {
local data = { local data = {
event = "onPlayerCommand", event = "onPlayerCommand",
args = { playerid = playerid,
playerid = playerid, command = command,
command = command, params = params
params = params
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerDamage", function(playerid, killerid, description) addEventHandler("onPlayerDamage", function(playerid, killerid, description)
{ {
local data = { local data = {
event = "onPlayerDamage", event = "onPlayerDamage",
args = { playerid = playerid,
playerid = playerid, killerid = killerid,
killerid = killerid, desc = {
obj_DamageDescription = { obj_name = "DamageDescription",
name = "desc", obj_data = _globalInstance._serializeObject(description)
data = _PyG2O_Serialize(description)
}
} }
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerDead", function(playerid, killerid) addEventHandler("onPlayerDead", function(playerid, killerid)
{ {
local data = { local data = {
event = "onPlayerDead", event = "onPlayerDead",
args = { playerid = playerid,
playerid = playerid, killerid = killerid
killerid = killerid
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerDisconnect", function(playerid, reason) addEventHandler("onPlayerDisconnect", function(playerid, reason)
{ {
local data = { local data = {
event = "onPlayerDisconnect", event = "onPlayerDisconnect",
args = { playerid = playerid,
playerid = playerid, reason = reason
reason = reason
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerDropItem", function(playerid, itemGround) addEventHandler("onPlayerDropItem", function(playerid, itemGround)
{ {
local data = { local data = {
event = "onPlayerDropItem", event = "onPlayerDropItem",
args = { playerid = playerid,
playerid = playerid, itemGround = {
obj_ItemGround = { obj_name = "ItemGround",
name = "itemGround", obj_data = _globalInstance._serializeObject(itemGround)
data = _PyG2O_Serialize(itemGround)
}
} }
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEnterWorld", function(playerid, world) addEventHandler("onPlayerEnterWorld", function(playerid, world)
{ {
local data = { local data = {
event = "onPlayerEnterWorld", event = "onPlayerEnterWorld",
args = { playerid = playerid,
playerid = playerid, world = world
world = world
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipAmulet", function(playerid, instance) addEventHandler("onPlayerEquipAmulet", function(playerid, instance)
{ {
local data = { local data = {
event = "onPlayerEquipAmulet", event = "onPlayerEquipAmulet",
args = { playerid = playerid,
playerid = playerid, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipArmor", function(playerid, instance) addEventHandler("onPlayerEquipArmor", function(playerid, instance)
{ {
local data = { local data = {
event = "onPlayerEquipArmor", event = "onPlayerEquipArmor",
args = { playerid = playerid,
playerid = playerid, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipBelt", function(playerid, instance) addEventHandler("onPlayerEquipBelt", function(playerid, instance)
{ {
local data = { local data = {
event = "onPlayerEquipBelt", event = "onPlayerEquipBelt",
args = { playerid = playerid,
playerid = playerid, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipHandItem", function(playerid, hand, instance) addEventHandler("onPlayerEquipHandItem", function(playerid, hand, instance)
{ {
local data = { local data = {
event = "onPlayerEquipHandItem", event = "onPlayerEquipHandItem",
args = { playerid = playerid,
playerid = playerid, hand = hand,
hand = hand, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipHelmet", function(playerid, instance) addEventHandler("onPlayerEquipHelmet", function(playerid, instance)
{ {
local data = { local data = {
event = "onPlayerEquipHelmet", event = "onPlayerEquipHelmet",
args = { playerid = playerid,
playerid = playerid, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipMeleeWeapon", function(playerid, instance) addEventHandler("onPlayerEquipMeleeWeapon", function(playerid, instance)
{ {
local data = { local data = {
event = "onPlayerEquipMeleeWeapon", event = "onPlayerEquipMeleeWeapon",
args = { playerid = playerid,
playerid = playerid, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipRangedWeapon", function(playerid, instance) addEventHandler("onPlayerEquipRangedWeapon", function(playerid, instance)
{ {
local data = { local data = {
event = "onPlayerEquipRangedWeapon", event = "onPlayerEquipRangedWeapon",
args = { playerid = playerid,
playerid = playerid, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipRing", function(playerid, handId, instance) addEventHandler("onPlayerEquipRing", function(playerid, handId, instance)
{ {
local data = { local data = {
event = "onPlayerEquipRing", event = "onPlayerEquipRing",
args = { playerid = playerid,
playerid = playerid, handId = handId,
handId = handId, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipShield", function(playerid, instance) addEventHandler("onPlayerEquipShield", function(playerid, instance)
{ {
local data = { local data = {
event = "onPlayerEquipShield", event = "onPlayerEquipShield",
args = { playerid = playerid,
playerid = playerid, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerEquipSpell", function(playerid, slotId, instance) addEventHandler("onPlayerEquipSpell", function(playerid, slotId, instance)
{ {
local data = { local data = {
event = "onPlayerEquipSpell", event = "onPlayerEquipSpell",
args = { playerid = playerid,
playerid = playerid, slotId = slotId,
slotId = slotId, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerJoin", function(playerid) addEventHandler("onPlayerJoin", function(playerid)
{ {
local data = { local data = {
event = "onPlayerJoin", event = "onPlayerJoin",
args = { playerid = playerid
playerid = playerid
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerMessage", function(playerid, message) addEventHandler("onPlayerMessage", function(playerid, message)
{ {
local data = { local data = {
event = "onPlayerMessage", event = "onPlayerMessage",
args = { playerid = playerid,
playerid = playerid, message = message
message = message
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerMobInteract", function(playerid, from, to) addEventHandler("onPlayerMobInteract", function(playerid, from, to)
{ {
local data = { local data = {
event = "onPlayerMobInteract", event = "onPlayerMobInteract",
args = { playerid = playerid,
playerid = playerid, from = from,
from = from, to = to
to = to
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerRespawn", function(playerid) addEventHandler("onPlayerRespawn", function(playerid)
{ {
local data = { local data = {
event = "onPlayerRespawn", event = "onPlayerRespawn",
args = { playerid = playerid
playerid = playerid
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerShoot", function(playerid, munition) addEventHandler("onPlayerShoot", function(playerid, munition)
{ {
local data = { local data = {
event = "onPlayerShoot", event = "onPlayerShoot",
args = { playerid = playerid,
playerid = playerid, munition = munition
munition = munition
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerSpellCast", function(playerid, instance, spellLevel) addEventHandler("onPlayerSpellCast", function(playerid, instance, spellLevel)
{ {
local data = { local data = {
event = "onPlayerSpellCast", event = "onPlayerSpellCast",
args = { playerid = playerid,
playerid = playerid, instance = instance,
instance = instance, spellLevel = spellLevel
spellLevel = spellLevel
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerSpellSetup", function(playerid, instance) addEventHandler("onPlayerSpellSetup", function(playerid, instance)
{ {
local data = { local data = {
event = "onPlayerSpellSetup", event = "onPlayerSpellSetup",
args = { playerid = playerid,
playerid = playerid, instance = instance
instance = instance
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerTakeItem", function(playerid, itemGround) addEventHandler("onPlayerTakeItem", function(playerid, itemGround)
{ {
local data = { local data = {
event = "onPlayerTakeItem", event = "onPlayerTakeItem",
args = { playerid = playerid,
playerid = playerid, itemGround = {
obj_ItemGround = { obj_name = "ItemGround",
name = "itemGround", obj_data = _globalInstance._serializeObject(itemGround)
data = _PyG2O_Serialize(itemGround)
}
} }
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerTeleport", function(playerid, vobName) addEventHandler("onPlayerTeleport", function(playerid, vobName)
{ {
local data = { local data = {
event = "onPlayerTeleport", event = "onPlayerTeleport",
args = { playerid = playerid,
playerid = playerid, vobName = vobName
vobName = vobName
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });
addEventHandler("onPlayerToggleFaceAni", function(playerid, aniName, toggle) addEventHandler("onPlayerToggleFaceAni", function(playerid, aniName, toggle)
{ {
local data = { local data = {
event = "onPlayerToggleFaceAni", event = "onPlayerToggleFaceAni",
args = { playerid = playerid,
playerid = playerid, aniName = aniName,
aniName = aniName, toggle = toggle
toggle = toggle
}
} }
_PyG2O_Send(data); if (_globalInstance != -1)
_globalInstance._send("event", data);
}); });

View File

@@ -1,126 +1,153 @@
local _pyg2o_server_connection = -1; _globalInstance <- -1;
local _silent = false;
local _url = -1
local _reconnect = false;
function PyG2O_Start(url, reconnect = false, silent = false) class PyG2O
{ {
_silent = silent; _connection = -1;
_url = url; _silent = false;
_reconnect = reconnect; _url = -1;
_reconnect_attempts = 0;
_max_reconnect_attempts = 0;
_pyg2o_server_connection = WebsocketClient(); _constantsInitialized = false;
_pyg2o_server_connection.silent = silent; _messageHandlers = null;
_pyg2o_server_connection.setUrl(url);
_pyg2o_server_connection.start();
if (!_silent) constructor(url, silent = false, max_reconnect_attempts = 0)
print("[PyG2O] Initializing connection on " + url)
}
function _PyG2O_Send(data)
{
if (_pyg2o_server_connection == -1)
return;
_pyg2o_server_connection.send(JSON.dump_ansi(data));
}
function _PyG2O_InitializeConstants()
{
local const_data = {
"type": "const_init",
"args": getconsttable()
};
_PyG2O_Send(const_data);
}
function _PyG2O_GetClassName(object)
{
if (object instanceof DamageDescription)
return "DamageDescription";
else if (object instanceof ItemGround)
return "ItemGround";
return null;
}
function _PyG2O_Serialize(object)
{
local cls = object.getclass();
local tab = {};
if (object instanceof DamageDescription)
{ {
tab["_flags"] <- object.flags; _url = url;
tab["_damage"] <- object.damage; _max_reconnect_attempts = max_reconnect_attempts;
tab["_item_instance"] <- object.item_instance; _silent = silent;
tab["_distance"] <- object.distance; _messageHandlers = {};
tab["_spell_id"] <- object.spell_id;
tab["_spell_level"] <- object.spell_level; _connection = WebsocketClient();
tab["_node"] <- object.node; _connection.silent = _silent;
} _connection.setUrl(_url);
else if (object instanceof ItemGround)
{ _connection.onOpen = _onOpen.bindenv(this);
tab["_id"] <- object.id; _connection.onClose = _onClose.bindenv(this);
tab["_instance"] <- object.instance; _connection.onMessage = _onMessage.bindenv(this);
tab["_amount"] <- object.amount;
tab["_world"] <- object.world; _registerMessage("call", _message_call.bindenv(this));
tab["_virtualWorld"] <- object.virtualWorld;
tab["_position"] <- object.getPosition(); if (_globalInstance == -1)
tab["_rotation"] <- object.getRotation(); _globalInstance = this;
} }
return tab; function start()
}
addEventHandler("onWebsocketConnect", function(socket, url)
{
if (socket != _pyg2o_server_connection)
return;
_PyG2O_InitializeConstants();
if (!_silent)
print("[PyG2O] Successfully connected to " + url);
});
addEventHandler("onWebsocketClose", function(socket, url, message)
{
if (socket != _pyg2o_server_connection || _reconnect)
return;
_pyg2o_server_connection = -1;
});
addEventHandler("onWebsocketMessage", function(socket, url, message)
{
if (socket != _pyg2o_server_connection)
return;
local request = JSON.parse_ansi(message);
if ("uuid" in request)
{ {
local result = compilestring(request["args"])(); _connection.start();
local className = _PyG2O_GetClassName(result); if (_connection.running)
if (className != null) print("[PyG2O] Initializing connection on " + _url);
{ }
className = format("obj_%s", className)
request["args"] = {}; function stop()
request["args"].rawset(className, {}); {
local objTab = request["args"].rawget(className); _connection.stop();
objTab["name"] <- "result"; if (!_connection.running)
objTab["data"] <- _PyG2O_Serialize(result); print("[PyG2O] Stopped connection");
}
function _registerMessage(type, handler)
{
if (type in _messageHandlers)
return;
_messageHandlers[type] <- handler;
}
function _callMessage(type, data)
{
if(!(type in _messageHandlers))
return;
_messageHandlers[type](data);
}
function _send(type, data, uuid = "none")
{
local sendData = {
"type": type,
"data": data,
"uuid": uuid
} }
else
{ _connection.send(JSON.dump_ansi(sendData, 2));
request["args"] =
{
"result": result
};
}
_pyg2o_server_connection.send(JSON.dump_ansi(request, 2));
} }
});
function _initializeConstants()
{
if (_constantsInitialized)
return;
_send("init_constants", getconsttable());
}
function _getClassName(object)
{
if (object instanceof DamageDescription)
return "DamageDescription";
else if (object instanceof ItemGround)
return "ItemGround";
return null;
}
function _serializeObject(object)
{
local cls = object.getclass();
local tab = {};
if (object instanceof DamageDescription)
{
tab["_flags"] <- object.flags;
tab["_damage"] <- object.damage;
tab["_item_instance"] <- object.item_instance;
tab["_distance"] <- object.distance;
tab["_spell_id"] <- object.spell_id;
tab["_spell_level"] <- object.spell_level;
tab["_node"] <- object.node;
}
else if (object instanceof ItemGround)
{
tab["_id"] <- object.id;
tab["_instance"] <- object.instance;
tab["_amount"] <- object.amount;
tab["_world"] <- object.world;
tab["_virtualWorld"] <- object.virtualWorld;
tab["_position"] <- object.getPosition();
tab["_rotation"] <- object.getRotation();
}
return tab;
}
function _onOpen(url)
{
_initializeConstants();
if (!_silent)
print("[PyG2O] Successfully connected to " + url);
}
function _onClose(url, message)
{
if (_max_reconnect_attempts == 0)
return;
_reconnect_attempts += 1;
if (_reconnect_attempts < _max_reconnect_attempts)
return;
_connection.stop();
}
function _onMessage(url, message)
{
local request = JSON.parse_ansi(message);
if (!("type" in request) ||
!("uuid" in request) ||
!("data" in request))
return;
_callMessage(request["type"], request);
}
}

16
include/messages.nut Normal file
View File

@@ -0,0 +1,16 @@
function _message_call(data)
{
local result = compilestring(data["data"])();
local className = _getClassName(result);
if (className != null)
{
data["data"] = {};
data["data"]["obj_name"] <- className;
data["data"]["obj_data"] <- _serializeObject(result);
}
else
data["data"] = result;
_send("result", data["data"], data["uuid"]);
}

View File

@@ -1,4 +1,5 @@
<server> <server>
<script src="messages.nut" type="server" />
<script src="main.nut" type="server" /> <script src="main.nut" type="server" />
<script src="events.nut" type="server" /> <script src="events.nut" type="server" />
</server> </server>

View File

@@ -20,14 +20,31 @@ class PythonWebsocketServer:
self.silent = silent self.silent = silent
self.logger = logger if logger is not None else logging.root self.logger = logger if logger is not None else logging.root
self.requests_list: dict[str, asyncio.Future] = dict() self._messageHandlers: dict[str, callable] = dict()
self._requests_list: dict[str, asyncio.Future] = dict()
self._stop_event: asyncio.Event = asyncio.Event() self._stop_event: asyncio.Event = asyncio.Event()
self.connected_socket: Optional[websockets.ClientConnection] = None self._connected_socket: Optional[websockets.ClientConnection] = None
self._registerMessage('event', self._message_event)
self._registerMessage('init_constants', self._message_init_constants)
self._registerMessage('result', self._message_call_result)
@classmethod @classmethod
async def get_server(cls): async def get_server(cls):
return cls._current_server return cls._current_server
def _registerMessage(self, type: str, handler: callable):
if type in self._messageHandlers:
return
self._messageHandlers[type] = handler
async def _callMessage(self, type: str, data: dict):
if type not in self._messageHandlers:
return
await self._messageHandlers[type](data)
async def start(self): async def start(self):
async with websockets.serve( async with websockets.serve(
self.handle_connection, self.handle_connection,
@@ -42,40 +59,75 @@ class PythonWebsocketServer:
async def stop(self): async def stop(self):
PythonWebsocketServer._current_server = None PythonWebsocketServer._current_server = None
self.connected_socket = None self._connected_socket = None
self._stop_event.set() self._stop_event.set()
async def make_request(self, data: str): async def make_request(self, data: str):
if (self.connected_socket is None): if (self._connected_socket is None):
return None return None
request_id = str(uuid.uuid4()) request_id = str(uuid.uuid4())
self.requests_list[request_id] = asyncio.get_running_loop().create_future() self._requests_list[request_id] = asyncio.get_running_loop().create_future()
request = { request = {
'type': 'call',
'uuid': request_id, 'uuid': request_id,
'args': data, 'data': data,
} }
request = json.dumps(request) request = json.dumps(request)
request = request.replace("'", '\\"')
formatted_request = request.replace("'", '\\"') await self._connected_socket.send(request)
formatted_request = formatted_request.replace("False", 'false')
formatted_request = formatted_request.replace("True", 'true')
await self.connected_socket.send(formatted_request)
result = await asyncio.wait_for( result = await asyncio.wait_for(
self.requests_list[request_id], self._requests_list[request_id],
timeout=30 timeout=30
) )
return result return result
async def _message_event(self, data: dict):
if (not isinstance(data['data'], dict) or
'event' not in data['data']):
return
eventName = data['data']['event']
del data['data']['event']
if 'desc' in data['data']:
obj_name = data['data']['desc']['obj_name']
obj_data = data['data']['desc']['obj_data']
data['data']['desc'] = _deserialize(obj_name, obj_data)
elif 'itemGround' in data['data']:
obj_name = data['data']['itemGround']['obj_name']
obj_data = data['data']['itemGround']['obj_data']
data['data']['itemGround'] = _deserialize(obj_name, obj_data)
asyncio.create_task(callEvent(eventName, **data['data']))
async def _message_init_constants(self, data: dict):
if data['data'] is not dict:
return
Constant._update(data['data'])
async def _message_call_result(self, data: dict):
if data['uuid'] not in self._requests_list:
return
result = data['data']
if (isinstance(data['data'], dict) and
'obj_name' in data['data'] and
'obj_data' in data['data']):
result = _deserialize(result['obj_name'], result['obj_data'])
self._requests_list[data['uuid']].set_result(result)
del self._requests_list[data['uuid']]
async def handle_connection(self, websocket: websockets.ClientConnection): async def handle_connection(self, websocket: websockets.ClientConnection):
if (websocket.remote_address[0] not in self.whitelist or self.connected_socket is not None): if (websocket.remote_address[0] not in self.whitelist or self._connected_socket is not None):
await websocket.close(4000, 'Connection denied') await websocket.close(4000, 'Connection denied')
return return
self.connected_socket = websocket self._connected_socket = websocket
self.is_connected = websocket self.is_connected = websocket
if (not self.silent): if (not self.silent):
self.logger.info(f'Client connected: {websocket.remote_address}') self.logger.info(f'Client connected: {websocket.remote_address}')
@@ -86,35 +138,12 @@ class PythonWebsocketServer:
async for message in websocket: async for message in websocket:
message_json = json.loads(message) message_json = json.loads(message)
if ('type' not in message_json or
'uuid' not in message_json or
'data' not in message_json):
return
# Deserializing objects await self._callMessage(message_json['type'], message_json)
if ('args' in message_json):
formatted_args = dict()
for key, value in message_json['args'].items():
if not key.startswith('obj_'):
formatted_args[key] = value
continue
formatted_args[value['name']] = _deserialize(key, value['data'])
message_json['args'] = formatted_args
# Processing events
if ('event' in message_json):
asyncio.create_task(callEvent(message_json['event'], **formatted_args))
continue
# Processing requests from Squirrel side
if ('type' in message_json):
Constant._update(message_json['args'])
continue
# Processing made requests
if (
'uuid' in message_json and
message_json['uuid'] in self.requests_list.keys()
):
self.requests_list[message_json['uuid']].set_result(next(iter(message_json['args'].values())))
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
self.logger.exception(f'[PyG2O] JSON Exception: {e}') self.logger.exception(f'[PyG2O] JSON Exception: {e}')
@@ -124,5 +153,5 @@ class PythonWebsocketServer:
if (not self.silent): if (not self.silent):
self.logger.info('Client disconnected') self.logger.info('Client disconnected')
self.is_connected = None self.is_connected = None
self.connected_socket = None self._connected_socket = None
asyncio.create_task(callEvent('onWebsocketDisconnect', **{})) asyncio.create_task(callEvent('onWebsocketDisconnect', **{}))