mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
commit
9ce60e7eff
|
|
@ -8540,19 +8540,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1219,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1097,
|
||||
"AbsX": 3096.68848,
|
||||
"AbsY": 3181.219,
|
||||
"AbsZ": 81.5115,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 676,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 796,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -8566,45 +8553,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1077,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 945,
|
||||
"AbsX": 3709.01025,
|
||||
"AbsY": 2115.38623,
|
||||
"AbsZ": 57.0175171,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 678,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 394,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 262,
|
||||
"AbsX": 3807.348,
|
||||
"AbsY": 5458.795,
|
||||
"AbsZ": 38.2669373,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 679,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 515,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 414,
|
||||
"AbsX": 4271.57471,
|
||||
"AbsY": 4504.82471,
|
||||
"AbsZ": 73.70659,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 680,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 936,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -8618,32 +8566,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 124,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 4,
|
||||
"AbsX": 4503.59473,
|
||||
"AbsY": 6168.89941,
|
||||
"AbsZ": 52.4856033,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 682,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 667,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 535,
|
||||
"AbsX": 4602.546,
|
||||
"AbsY": 3341.289,
|
||||
"AbsZ": 37.3147659,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 683,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 242,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
|
|||
|
|
@ -10256,32 +10256,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 2157,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 2056,
|
||||
"AbsX": 1896.58,
|
||||
"AbsY": 2983.99878,
|
||||
"AbsZ": 52.99063,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 812,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 972,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 852,
|
||||
"AbsX": 2434.74072,
|
||||
"AbsY": 3695.22168,
|
||||
"AbsZ": 35.8926926,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 813,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1211,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -10308,58 +10282,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 551,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 419,
|
||||
"AbsX": 3499.93652,
|
||||
"AbsY": 4014.81616,
|
||||
"AbsZ": 13.9436874,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 816,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 843,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 723,
|
||||
"AbsX": 3972.74072,
|
||||
"AbsY": 5945.22168,
|
||||
"AbsZ": 33.9761276,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 817,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 105,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 4,
|
||||
"AbsX": 4488.001,
|
||||
"AbsY": 3474.57983,
|
||||
"AbsZ": 42.84017,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 818,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 703,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 571,
|
||||
"AbsX": 4520.795,
|
||||
"AbsY": 2592.652,
|
||||
"AbsZ": 14.5540581,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 819,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 247,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -10373,32 +10295,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1351,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1231,
|
||||
"AbsX": 5602.91162,
|
||||
"AbsY": 2873.561,
|
||||
"AbsZ": 31.6628265,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 821,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 399,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 267,
|
||||
"AbsX": 6707.348,
|
||||
"AbsY": 2332.795,
|
||||
"AbsZ": 113.330261,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 822,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 2148,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -15508,32 +15508,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 781,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 661,
|
||||
"AbsX": 579.2592,
|
||||
"AbsY": 7032.77832,
|
||||
"AbsZ": 54.5858879,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1234,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 2289,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 2157,
|
||||
"AbsX": 621.848267,
|
||||
"AbsY": 2375.897,
|
||||
"AbsZ": 38.1845856,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1235,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 109,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -15547,19 +15521,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 230,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 129,
|
||||
"AbsX": 1193.9021,
|
||||
"AbsY": 4565.57031,
|
||||
"AbsZ": 72.3534,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1237,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1302,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -15573,32 +15534,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1063,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 943,
|
||||
"AbsX": 2755.58032,
|
||||
"AbsY": 1433.88428,
|
||||
"AbsZ": 58.6747551,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1239,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1173,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1072,
|
||||
"AbsX": 2962.00122,
|
||||
"AbsY": 2320.57983,
|
||||
"AbsZ": 72.81362,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1240,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 2008,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -15612,71 +15547,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 383,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 251,
|
||||
"AbsX": 4202.795,
|
||||
"AbsY": 6984.652,
|
||||
"AbsZ": 38.1436462,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1242,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1856,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1734,
|
||||
"AbsX": 4988.68848,
|
||||
"AbsY": 4439.21875,
|
||||
"AbsZ": 60.90174,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1243,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 652,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 532,
|
||||
"AbsX": 5045.78662,
|
||||
"AbsY": 5840.68945,
|
||||
"AbsZ": 51.4351578,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1244,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 922,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 790,
|
||||
"AbsX": 5172.795,
|
||||
"AbsY": 3356.652,
|
||||
"AbsZ": 32.1784973,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1245,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 512,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 403,
|
||||
"AbsX": 5638.105,
|
||||
"AbsY": 6598.934,
|
||||
"AbsZ": 57.89732,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1246,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 2137,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -15703,32 +15573,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1443,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1323,
|
||||
"AbsX": 7037.47266,
|
||||
"AbsY": 1186.01941,
|
||||
"AbsZ": 51.6652679,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1249,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1561,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1452,
|
||||
"AbsX": 7331.6543,
|
||||
"AbsY": 3069.78076,
|
||||
"AbsZ": 69.8796158,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 1250,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 760,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -12076,58 +12076,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 266,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 146,
|
||||
"AbsX": 928.198,
|
||||
"AbsY": 5564.63672,
|
||||
"AbsZ": 67.040596,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 954,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 407,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 275,
|
||||
"AbsX": 1742.43945,
|
||||
"AbsY": 5716.78564,
|
||||
"AbsZ": 23.85953,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 955,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 126,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 4,
|
||||
"AbsX": 2746.68848,
|
||||
"AbsY": 4419.21875,
|
||||
"AbsZ": 46.284523,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 956,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1359,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1239,
|
||||
"AbsX": 3070.05664,
|
||||
"AbsY": 2282.41748,
|
||||
"AbsZ": 65.20178,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 957,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 536,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -12154,32 +12102,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1469,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1368,
|
||||
"AbsX": 3986.8877,
|
||||
"AbsY": 2494.16553,
|
||||
"AbsZ": 94.4665756,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 960,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 676,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 556,
|
||||
"AbsX": 4336.439,
|
||||
"AbsY": 5866.91162,
|
||||
"AbsZ": 72.2181549,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 961,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1621,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -12193,45 +12115,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 938,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 837,
|
||||
"AbsX": 4818.013,
|
||||
"AbsY": 5254.69775,
|
||||
"AbsZ": 80.30203,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 963,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1078,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 958,
|
||||
"AbsX": 6638.752,
|
||||
"AbsY": 4596.15527,
|
||||
"AbsZ": 40.2804756,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 964,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1219,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1087,
|
||||
"AbsX": 6998.91943,
|
||||
"AbsY": 5326.044,
|
||||
"AbsZ": 21.9767818,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 965,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 245,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -8969,32 +8969,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1219,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1110,
|
||||
"AbsX": 2700.56641,
|
||||
"AbsY": 2938.72949,
|
||||
"AbsZ": 60.2481575,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 711,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 959,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 839,
|
||||
"AbsX": 3376.60767,
|
||||
"AbsY": 2457.89429,
|
||||
"AbsZ": 50.8711739,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 712,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 136,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -9008,45 +8982,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1090,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 968,
|
||||
"AbsX": 3664.68848,
|
||||
"AbsY": 4789.21875,
|
||||
"AbsZ": 64.9002762,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 714,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 288,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 156,
|
||||
"AbsX": 4365.159,
|
||||
"AbsY": 4282.131,
|
||||
"AbsZ": 60.087677,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 715,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1817,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1716,
|
||||
"AbsX": 4649.79736,
|
||||
"AbsY": 2642.05566,
|
||||
"AbsZ": 70.51741,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 716,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 819,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -9060,32 +8995,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 580,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 460,
|
||||
"AbsX": 5467.6167,
|
||||
"AbsY": 3842.79272,
|
||||
"AbsZ": 55.66716,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 718,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 690,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 589,
|
||||
"AbsX": 5904.2207,
|
||||
"AbsY": 4439.24854,
|
||||
"AbsZ": 69.2569962,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 719,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 440,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
|
|||
|
|
@ -9346,45 +9346,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1063,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 931,
|
||||
"AbsX": 2961.79932,
|
||||
"AbsY": 2185.03418,
|
||||
"AbsZ": 221.338272,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 738,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 391,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 271,
|
||||
"AbsX": 3254.05664,
|
||||
"AbsY": 5804.41748,
|
||||
"AbsZ": 229.117279,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 739,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 641,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 521,
|
||||
"AbsX": 3631.02051,
|
||||
"AbsY": 3791.069,
|
||||
"AbsZ": 217.111908,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 740,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 501,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -9411,32 +9372,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 251,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 129,
|
||||
"AbsX": 3996.68848,
|
||||
"AbsY": 4335.21875,
|
||||
"AbsZ": 273.429138,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 743,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 109,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 0,
|
||||
"AbsX": 4421.5625,
|
||||
"AbsY": 3720.8457,
|
||||
"AbsZ": 225.8448,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 744,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1215,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -9450,19 +9385,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 770,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 650,
|
||||
"AbsX": 5926.77832,
|
||||
"AbsY": 3396.74072,
|
||||
"AbsZ": 91.09625,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 746,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1048,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -11608,19 +11608,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 653,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 533,
|
||||
"AbsX": 910.7408,
|
||||
"AbsY": 2667.22168,
|
||||
"AbsZ": 68.7458649,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 920,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1454,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -11634,71 +11621,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1575,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1474,
|
||||
"AbsX": 2006.28674,
|
||||
"AbsY": 5523.80127,
|
||||
"AbsZ": 82.80721,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 922,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1727,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1595,
|
||||
"AbsX": 2346.10083,
|
||||
"AbsY": 1945.51868,
|
||||
"AbsZ": 69.6338654,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 923,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 513,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 404,
|
||||
"AbsX": 2915.07471,
|
||||
"AbsY": 3768.05469,
|
||||
"AbsZ": 62.5202637,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 924,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 126,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 4,
|
||||
"AbsX": 3224.68848,
|
||||
"AbsY": 7367.21875,
|
||||
"AbsZ": 84.523674,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 925,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 395,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 275,
|
||||
"AbsX": 3324.40527,
|
||||
"AbsY": 4578.996,
|
||||
"AbsZ": 69.99102,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 926,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1302,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -11712,32 +11634,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 266,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 146,
|
||||
"AbsX": 3992.53369,
|
||||
"AbsY": 6048.867,
|
||||
"AbsZ": 54.7470245,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 928,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 900,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 791,
|
||||
"AbsX": 4019.30933,
|
||||
"AbsY": 1613.07593,
|
||||
"AbsZ": 75.31056,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 929,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1052,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -11751,32 +11647,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 782,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 662,
|
||||
"AbsX": 5400.74072,
|
||||
"AbsY": 2541.22168,
|
||||
"AbsZ": 48.0176964,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 931,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1181,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1072,
|
||||
"AbsX": 6832.797,
|
||||
"AbsY": 4254.491,
|
||||
"AbsZ": 53.264,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 932,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 632,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -8683,32 +8683,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 645,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 525,
|
||||
"AbsX": 2226.74072,
|
||||
"AbsY": 3381.22168,
|
||||
"AbsZ": 47.1299973,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 687,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 763,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 654,
|
||||
"AbsX": 2532.84058,
|
||||
"AbsY": 4528.31738,
|
||||
"AbsZ": 50.48315,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 688,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 915,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -8735,32 +8709,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 376,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 275,
|
||||
"AbsX": 3904.129,
|
||||
"AbsY": 4695.489,
|
||||
"AbsZ": 63.15471,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 691,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1219,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1087,
|
||||
"AbsX": 3958.74463,
|
||||
"AbsY": 2196.716,
|
||||
"AbsZ": 45.3599777,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 692,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1067,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -8774,32 +8722,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 266,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 146,
|
||||
"AbsX": 4748.437,
|
||||
"AbsY": 5469.24854,
|
||||
"AbsZ": 48.33355,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 694,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 516,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 396,
|
||||
"AbsX": 5497.22266,
|
||||
"AbsY": 3957.127,
|
||||
"AbsZ": 45.2092972,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 695,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 624,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -12297,84 +12297,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1760,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1640,
|
||||
"AbsX": 1224.89941,
|
||||
"AbsY": 4202.40527,
|
||||
"AbsZ": 54.66005,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 975,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1870,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1769,
|
||||
"AbsX": 1742.0011,
|
||||
"AbsY": 5306.58,
|
||||
"AbsZ": 77.51988,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 976,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 731,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 611,
|
||||
"AbsX": 3749.88428,
|
||||
"AbsY": 5510.41943,
|
||||
"AbsZ": 230.786942,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 977,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1478,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1369,
|
||||
"AbsX": 3756.67651,
|
||||
"AbsY": 2149.56226,
|
||||
"AbsZ": 66.70892,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 978,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 287,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 155,
|
||||
"AbsX": 3765.75122,
|
||||
"AbsY": 2659.72437,
|
||||
"AbsZ": 135.187622,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 979,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1110,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 990,
|
||||
"AbsX": 4018.3623,
|
||||
"AbsY": 4194.70264,
|
||||
"AbsZ": 199.684,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 980,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1349,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -12388,19 +12310,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 439,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 307,
|
||||
"AbsX": 4610.795,
|
||||
"AbsY": 5718.652,
|
||||
"AbsZ": 174.196381,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 982,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 841,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -12414,19 +12323,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1220,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1119,
|
||||
"AbsX": 4890.966,
|
||||
"AbsY": 4531.238,
|
||||
"AbsZ": 222.527054,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 984,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 135,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -12440,45 +12336,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 970,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 861,
|
||||
"AbsX": 5289.592,
|
||||
"AbsY": 5012.38135,
|
||||
"AbsZ": 246.0418,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 986,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1620,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1498,
|
||||
"AbsX": 5819.02344,
|
||||
"AbsY": 2305.157,
|
||||
"AbsZ": 97.94419,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 987,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 591,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 459,
|
||||
"AbsX": 6428.63965,
|
||||
"AbsY": 5190.393,
|
||||
"AbsZ": 39.42817,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 988,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1739,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -10932,45 +10932,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 528,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 396,
|
||||
"AbsX": 2734.795,
|
||||
"AbsY": 2374.652,
|
||||
"AbsZ": 41.2234421,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 866,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 961,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 829,
|
||||
"AbsX": 3390.795,
|
||||
"AbsY": 5754.652,
|
||||
"AbsZ": 32.0256653,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 867,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 247,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 146,
|
||||
"AbsX": 3507.72119,
|
||||
"AbsY": 2540.61621,
|
||||
"AbsZ": 62.4884148,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 868,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1082,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -10997,58 +10958,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1351,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1231,
|
||||
"AbsX": 4675.94336,
|
||||
"AbsY": 6243.58252,
|
||||
"AbsZ": 64.11465,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 871,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1211,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1102,
|
||||
"AbsX": 4686.31738,
|
||||
"AbsY": 5569.15967,
|
||||
"AbsZ": 78.99428,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 872,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 2403,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 2294,
|
||||
"AbsX": 4902.087,
|
||||
"AbsY": 3510.83838,
|
||||
"AbsZ": 54.2062263,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 873,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 680,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 548,
|
||||
"AbsX": 5534.78564,
|
||||
"AbsY": 2273.56055,
|
||||
"AbsZ": 46.44301,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 874,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 820,
|
||||
"ObjectName": "llm_socket",
|
||||
|
|
@ -11062,32 +10971,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 126,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 4,
|
||||
"AbsX": 6312.68848,
|
||||
"AbsY": 5329.21875,
|
||||
"AbsZ": 68.8674545,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 876,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 1492,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 1360,
|
||||
"AbsX": 6643.15137,
|
||||
"AbsY": 4448.6543,
|
||||
"AbsZ": 40.43171,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 877,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 513,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -1169,19 +1169,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 122,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 0,
|
||||
"AbsX": 1974.68848,
|
||||
"AbsY": 2035.21887,
|
||||
"AbsZ": 42.69806,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 93,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 109,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -3782,45 +3782,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 449,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 317,
|
||||
"AbsX": 1739.221,
|
||||
"AbsY": 1776.55054,
|
||||
"AbsZ": 74.7683,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 298,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 299,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 198,
|
||||
"AbsX": 1839.926,
|
||||
"AbsY": 2669.99561,
|
||||
"AbsZ": 105.1724,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 299,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 831,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 722,
|
||||
"AbsX": 2672.99951,
|
||||
"AbsY": 2277.26343,
|
||||
"AbsZ": 97.5842,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 300,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 434,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -3249,45 +3249,6 @@
|
|||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 693,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 561,
|
||||
"AbsX": 1273.68921,
|
||||
"AbsY": 2544.30444,
|
||||
"AbsZ": 72.1122742,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 257,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 246,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 145,
|
||||
"AbsX": 1496.34106,
|
||||
"AbsY": 1233.22192,
|
||||
"AbsZ": 103.060211,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 258,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 127,
|
||||
"ObjectName": "llm_socket",
|
||||
"ObjectType": "llm_socket",
|
||||
"Owner": 18,
|
||||
"AbsX": 2862.687,
|
||||
"AbsY": 2759.684,
|
||||
"AbsZ": 95.47642,
|
||||
"Yaw": 0.0,
|
||||
"GUID": 259,
|
||||
"MapID": null,
|
||||
"IsChildObject": true
|
||||
},
|
||||
{
|
||||
"Id": 678,
|
||||
"ObjectName": "lock_external",
|
||||
|
|
|
|||
|
|
@ -404,6 +404,8 @@ class ChatActor(
|
|||
case ("nc", pos) => Some(PlanetSideEmpire.NC, pos)
|
||||
case ("vs", pos) => Some(PlanetSideEmpire.VS, pos)
|
||||
case ("none", pos) => Some(PlanetSideEmpire.NEUTRAL, pos)
|
||||
case ("bo", pos) => Some(PlanetSideEmpire.NEUTRAL, pos)
|
||||
case ("neutral", pos) => Some(PlanetSideEmpire.NEUTRAL, pos)
|
||||
case _ => None
|
||||
}
|
||||
.headOption match {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,11 @@
|
|||
package net.psforever.actors.session
|
||||
|
||||
import akka.actor.typed
|
||||
import akka.actor.typed.receptionist.Receptionist
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
|
||||
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware, typed}
|
||||
import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
import net.psforever.actors.net.MiddlewareActor
|
||||
import net.psforever.services.ServiceManager.Lookup
|
||||
import net.psforever.objects.locker.LockerContainer
|
||||
import org.log4s.MDC
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.{Await, Future}
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.Success
|
||||
import net.psforever.login.WorldSession._
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.avatar._
|
||||
|
|
@ -27,7 +17,7 @@ import net.psforever.objects.entity.{SimpleWorldEntity, WorldEntity}
|
|||
import net.psforever.objects.equipment._
|
||||
import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver}
|
||||
import net.psforever.objects.inventory.{Container, InventoryItem}
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.objects.locker.LockerContainer
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.serverobject.containable.Containable
|
||||
import net.psforever.objects.serverobject.damage.Damageable
|
||||
|
|
@ -35,6 +25,7 @@ import net.psforever.objects.serverobject.deploy.Deployment
|
|||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.serverobject.generator.Generator
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
||||
import net.psforever.objects.serverobject.locks.IFFLock
|
||||
import net.psforever.objects.serverobject.mblocker.Locker
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
|
|
@ -47,9 +38,10 @@ import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
|
|||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
|
||||
import net.psforever.objects.serverobject.zipline.ZipLinePath
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.objects.teamwork.Squad
|
||||
import net.psforever.objects.vehicles._
|
||||
import net.psforever.objects.vehicles.Utility.InternalTelepad
|
||||
import net.psforever.objects.vehicles._
|
||||
import net.psforever.objects.vital._
|
||||
import net.psforever.objects.vital.base._
|
||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||
|
|
@ -57,14 +49,14 @@ import net.psforever.objects.vital.projectile.ProjectileReason
|
|||
import net.psforever.objects.zones.{Zone, ZoneHotSpotProjector, Zoning}
|
||||
import net.psforever.packet._
|
||||
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
||||
import net.psforever.packet.game.{HotSpotInfo => PacketHotSpotInfo, _}
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
import net.psforever.services.ServiceManager.LookupResult
|
||||
import net.psforever.packet.game.{HotSpotInfo => PacketHotSpotInfo, _}
|
||||
import net.psforever.services.ServiceManager.{Lookup, LookupResult}
|
||||
import net.psforever.services.account.{AccountPersistenceService, PlayerToken, ReceiveAccountData, RetrieveAccountData}
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage, AvatarServiceResponse}
|
||||
import net.psforever.services.chat.ChatService
|
||||
import net.psforever.services.galaxy.{GalaxyAction, GalaxyResponse, GalaxyServiceMessage, GalaxyServiceResponse}
|
||||
import net.psforever.services.local.support.{HackCaptureActor, RouterTelepadActivation}
|
||||
import net.psforever.services.local.support.{CaptureFlagManager, HackCaptureActor, RouterTelepadActivation}
|
||||
import net.psforever.services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse}
|
||||
import net.psforever.services.properties.PropertyOverrideManager
|
||||
import net.psforever.services.support.SupportActor
|
||||
|
|
@ -75,6 +67,13 @@ import net.psforever.services.{RemoverActor, Service, ServiceManager, Interstell
|
|||
import net.psforever.types._
|
||||
import net.psforever.util.{Config, DefinitionUtil}
|
||||
import net.psforever.zones.Zones
|
||||
import org.log4s.MDC
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.{Await, Future}
|
||||
import scala.util.Success
|
||||
|
||||
object SessionActor {
|
||||
sealed trait Command
|
||||
|
|
@ -203,6 +202,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
var setupAvatarFunc: () => Unit = AvatarCreate
|
||||
var setCurrentAvatarFunc: Player => Unit = SetCurrentAvatarNormally
|
||||
var persist: () => Unit = NoPersistence
|
||||
var specialItemSlotGuid : Option[PlanetSideGUID] = None // If a special item (e.g. LLU) has been attached to the player the GUID should be stored here, or cleared when dropped, since the drop hotkey doesn't send the GUID of the object to be dropped.
|
||||
|
||||
/**
|
||||
* used during zone transfers to maintain reference to seated vehicle (which does not yet exist in the new zone)
|
||||
|
|
@ -555,6 +555,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
case GalaxyResponse.MapUpdate(msg) =>
|
||||
sendResponse(msg)
|
||||
|
||||
case GalaxyResponse.FlagMapUpdate(msg) =>
|
||||
sendResponse(msg)
|
||||
|
||||
case GalaxyResponse.TransferPassenger(temp_channel, vehicle, vehicle_to_delete, manifest) =>
|
||||
(manifest.passengers.find { case (name, _) => player.Name.equals(name) } match {
|
||||
case Some((name, index)) if vehicle.Seats(index).occupant.isEmpty =>
|
||||
|
|
@ -968,6 +971,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
CancelZoningProcess()
|
||||
PlayerActionsToCancel()
|
||||
CancelAllProximityUnits()
|
||||
DropSpecialSlotItem()
|
||||
continent.Population ! Zone.Population.Release(avatar)
|
||||
response match {
|
||||
case Some((zone, spawnPoint)) =>
|
||||
|
|
@ -1802,6 +1806,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
||||
}
|
||||
|
||||
case AvatarResponse.DropSpecialItem() =>
|
||||
DropSpecialSlotItem()
|
||||
|
||||
case AvatarResponse.Killed(mount) =>
|
||||
val respawnTimer = 300.seconds
|
||||
//drop free hand item
|
||||
|
|
@ -1810,25 +1817,32 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
DropEquipmentFromInventory(player)(item)
|
||||
case None => ;
|
||||
}
|
||||
|
||||
DropSpecialSlotItem()
|
||||
ToggleMaxSpecialState(enable = false)
|
||||
|
||||
keepAliveFunc = NormalKeepAlive
|
||||
zoningStatus = Zoning.Status.None
|
||||
deadState = DeadState.Dead
|
||||
|
||||
continent.GUID(mount) match {
|
||||
case Some(obj: Vehicle) =>
|
||||
TotalDriverVehicleControl(obj)
|
||||
UnaccessContainer(obj)
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
PlayerActionsToCancel()
|
||||
CancelAllProximityUnits()
|
||||
CancelZoningProcessWithDescriptiveReason("cancel")
|
||||
|
||||
if (shotsWhileDead > 0) {
|
||||
log.warn(
|
||||
s"KillPlayer/SHOTS_WHILE_DEAD: client of ${avatar.name} fired $shotsWhileDead rounds while character was dead on server"
|
||||
)
|
||||
shotsWhileDead = 0
|
||||
}
|
||||
|
||||
reviveTimer.cancel()
|
||||
if (player.death_by == 0) {
|
||||
reviveTimer = context.system.scheduler.scheduleOnce(respawnTimer) {
|
||||
|
|
@ -2133,6 +2147,28 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
}
|
||||
}
|
||||
|
||||
def DropSpecialSlotItem(): Unit = {
|
||||
specialItemSlotGuid match {
|
||||
case Some(guid: PlanetSideGUID) =>
|
||||
specialItemSlotGuid = None
|
||||
continent.GUID(guid) match {
|
||||
case Some(llu: CaptureFlag) =>
|
||||
llu.Carrier match {
|
||||
case Some(carrier: Player) if carrier.GUID == player.GUID =>
|
||||
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
|
||||
case Some(carrier: Player) =>
|
||||
log.warn(s"${player.toString} tried to drop LLU, but it is currently held by ${carrier.toString}")
|
||||
case None =>
|
||||
log.warn(s"${player.toString} tried to drop LLU, but nobody is holding it.")
|
||||
}
|
||||
case _ =>
|
||||
log.warn(s"${player.toString} Tried to drop a special item that wasn't recognized. GUID: $guid")
|
||||
}
|
||||
|
||||
case _ => ; // Nothing to drop, do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce constraints on bulk purchases as determined by a given player's previous purchase times and hard acquisition delays.
|
||||
* Intended to assist in sanitizing loadout information from the perspective of the player, or target owner.
|
||||
|
|
@ -2290,6 +2326,40 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
case LocalResponse.SendPlanetsideAttributeMessage(target_guid, attribute_number, attribute_value) =>
|
||||
SendPlanetsideAttributeMessage(target_guid, attribute_number, attribute_value)
|
||||
|
||||
case LocalResponse.SendGenericObjectActionMessage(target_guid, action_number) =>
|
||||
sendResponse(GenericObjectActionMessage(target_guid, action_number))
|
||||
|
||||
case LocalResponse.SendGenericActionMessage(action_number) =>
|
||||
sendResponse(GenericActionMessage(action_number))
|
||||
|
||||
case LocalResponse.SendChatMsg(msg) =>
|
||||
sendResponse(msg)
|
||||
|
||||
case LocalResponse.SendPacket(packet) =>
|
||||
sendResponse(packet)
|
||||
|
||||
case LocalResponse.LluSpawned(llu) =>
|
||||
// Create LLU on client
|
||||
sendResponse(ObjectCreateMessage(
|
||||
llu.Definition.ObjectId,
|
||||
llu.GUID,
|
||||
llu.Definition.Packet.ConstructorData(llu).get
|
||||
))
|
||||
|
||||
sendResponse(TriggerSoundMessage(TriggeredSound.LLUMaterialize, llu.Position, unk = 20, 0.8000001f))
|
||||
|
||||
case LocalResponse.LluDespawned(llu) =>
|
||||
sendResponse(TriggerSoundMessage(TriggeredSound.LLUDeconstruct, llu.Position, unk = 20, 0.8000001f))
|
||||
sendResponse(ObjectDeleteMessage(llu.GUID, 0))
|
||||
|
||||
// If the player was holding the LLU, remove it from their tracked special item slot
|
||||
specialItemSlotGuid match {
|
||||
case Some(guid) =>
|
||||
if (guid == llu.GUID) {
|
||||
specialItemSlotGuid = None
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
case LocalResponse.ObjectDelete(object_guid, unk) =>
|
||||
if (tplayer_guid != guid) {
|
||||
sendResponse(ObjectDeleteMessage(object_guid, unk))
|
||||
|
|
@ -4144,7 +4214,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
case None =>
|
||||
log.warn(s"DropItem: ${player.Name} wanted to drop a $anItem, but it wasn't at hand")
|
||||
}
|
||||
case Some(obj) => //TODO LLU
|
||||
case Some(obj) =>
|
||||
log.warn(s"DropItem: ${player.Name} wanted to drop a $obj, but that isn't possible")
|
||||
case None =>
|
||||
sendResponse(ObjectDeleteMessage(item_guid, 0)) //this is fine; item doesn't exist to the server anyway
|
||||
|
|
@ -4719,7 +4789,16 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
case Some(item) =>
|
||||
CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||
captureTerminal.Actor ! CommonMessages.Use(player, Some(item))
|
||||
case _ => ;
|
||||
case _ if specialItemSlotGuid.nonEmpty =>
|
||||
continent.GUID(specialItemSlotGuid) match {
|
||||
case Some(llu: CaptureFlag) =>
|
||||
if (llu.Target.GUID == captureTerminal.Owner.GUID) {
|
||||
continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.LluCaptured(llu))
|
||||
} else {
|
||||
log.info(s"LLU target is not this base. Target GUID: ${llu.Target.GUID} This base: ${captureTerminal.Owner.GUID}")
|
||||
}
|
||||
case _ => log.warn("Item in specialItemSlotGuid is not registered with continent or is not a LLU")
|
||||
}
|
||||
}
|
||||
|
||||
case Some(obj: FacilityTurret) =>
|
||||
|
|
@ -4945,6 +5024,19 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
case None => ;
|
||||
}
|
||||
|
||||
case Some(obj: CaptureFlag) =>
|
||||
// LLU can normally only be picked up the faction that owns it
|
||||
if (specialItemSlotGuid.isEmpty) {
|
||||
if(obj.Faction == player.Faction) {
|
||||
specialItemSlotGuid = Some(obj.GUID)
|
||||
continent.LocalEvents ! CaptureFlagManager.PickupFlag(obj, player)
|
||||
} else {
|
||||
log.warn(s"Player ${player.toString} tried to pick up LLU ${obj.GUID} - ${obj.Faction} that doesn't belong to their faction")
|
||||
}
|
||||
} else if(specialItemSlotGuid.get != obj.GUID) { // Ignore duplicate pickup requests
|
||||
log.warn(s"Player ${player.toString} tried to pick up LLU ${obj.GUID} - ${obj.Faction} but their special slot already contains $specialItemSlotGuid")
|
||||
}
|
||||
|
||||
case Some(obj) =>
|
||||
CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||
log.warn(s"UseItem: ${player.Name} does not know how to handle $obj")
|
||||
|
|
@ -5048,6 +5140,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
log.info(s"${player.Name} is back")
|
||||
player.AwayFromKeyboard = false
|
||||
}
|
||||
if (action == GenericActionEnum.DropSpecialItem.id) {
|
||||
DropSpecialSlotItem()
|
||||
}
|
||||
if (action == 15) { //max deployment
|
||||
log.info(s"${player.Name} has anchored ${player.Sex.pronounObject}self to the ground")
|
||||
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
|
||||
|
|
@ -6715,11 +6810,13 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
//sync model access state
|
||||
sendResponse(PlanetsideAttributeMessage(amenityId, 50, 0))
|
||||
sendResponse(PlanetsideAttributeMessage(amenityId, 51, 0))
|
||||
|
||||
//sync damageable, if
|
||||
val health = amenity.Health
|
||||
if (amenity.Definition.Damageable && health < amenity.MaxHealth) {
|
||||
sendResponse(PlanetsideAttributeMessage(amenityId, 0, health))
|
||||
}
|
||||
|
||||
//sync special object type cases
|
||||
amenity match {
|
||||
case silo: ResourceSilo =>
|
||||
|
|
@ -6733,19 +6830,30 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
case door: Door if door.isOpen =>
|
||||
sendResponse(GenericObjectStateMsg(amenityId, 16))
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
//sync hack state
|
||||
amenity match {
|
||||
case obj: Hackable if obj.HackedBy.nonEmpty =>
|
||||
//sync hack state
|
||||
amenity.Definition match {
|
||||
case GlobalDefinitions.capture_terminal =>
|
||||
SendPlanetsideAttributeMessage(
|
||||
amenity.GUID,
|
||||
PlanetsideAttributeEnum.ControlConsoleHackUpdate,
|
||||
HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false))
|
||||
case _ =>
|
||||
HackObject(amenity.GUID, 1114636288L, 8L) //generic hackable object
|
||||
case GlobalDefinitions.capture_terminal =>
|
||||
SendPlanetsideAttributeMessage(
|
||||
amenity.GUID,
|
||||
PlanetsideAttributeEnum.ControlConsoleHackUpdate,
|
||||
HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false))
|
||||
case _ =>
|
||||
HackObject(amenity.GUID, 1114636288L, 8L) //generic hackable object
|
||||
}
|
||||
|
||||
// sync capture flags
|
||||
case llu: CaptureFlag =>
|
||||
// Create LLU
|
||||
sendResponse(ObjectCreateMessage(
|
||||
llu.Definition.ObjectId,
|
||||
llu.GUID,
|
||||
llu.Definition.Packet.ConstructorData(llu).get
|
||||
))
|
||||
|
||||
// Attach it to a player if it has a carrier
|
||||
if (llu.Carrier.nonEmpty) {
|
||||
continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.SendPacket(ObjectAttachMessage(llu.Carrier.get.GUID, llu.GUID, 252)))
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, Ca
|
|||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.persistence
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, PlanetSideGeneratorState}
|
||||
import net.psforever.util.Database._
|
||||
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
|
||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||
import net.psforever.services.{InterstellarClusterService, Service, ServiceManager}
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, PlanetSideGeneratorState}
|
||||
import net.psforever.util.Database._
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success}
|
||||
|
|
@ -197,8 +197,8 @@ class BuildingActor(
|
|||
|
||||
case AmenityStateChange(gen: Generator, data) =>
|
||||
if (generatorStateChange(gen, data)) {
|
||||
//update the map
|
||||
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||
// Request all buildings update their map data to refresh lattice linked benefits
|
||||
zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||
}
|
||||
Behaviors.same
|
||||
|
||||
|
|
@ -364,7 +364,7 @@ class BuildingActor(
|
|||
}
|
||||
building.Faction = faction
|
||||
alignForceDomeStatus(mapUpdateOnChange = false)
|
||||
galaxy ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||
zone.actor ! ZoneActor.ZoneMapUpdate() // Update entire lattice to show lattice benefits
|
||||
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SetEmpire(building.GUID, faction))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import net.psforever.objects.vital.prop.DamageWithPosition
|
|||
import net.psforever.objects.vital.{ComplexDeployableResolutions, MaxResolutions, SimpleResolutions}
|
||||
import net.psforever.types.{ExoSuitType, ImplantType, PlanetSideEmpire, Vector3}
|
||||
import net.psforever.types._
|
||||
import net.psforever.objects.serverobject.llu.{CaptureFlagDefinition, CaptureFlagSocketDefinition}
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
|
|
@ -1069,6 +1070,11 @@ object GlobalDefinitions {
|
|||
|
||||
val vanu_control_console = new CaptureTerminalDefinition(930) // Cavern CC
|
||||
|
||||
val llm_socket = new CaptureFlagSocketDefinition()
|
||||
|
||||
val capture_flag = new CaptureFlagDefinition()
|
||||
capture_flag.Packet = new CaptureFlagConverter
|
||||
|
||||
val lodestar_repair_terminal = new MedicalTerminalDefinition(461)
|
||||
|
||||
val multivehicle_rearm_terminal = new OrderTerminalDefinition(576)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ object ObjectType extends Enumeration {
|
|||
val BoomerTrigger = "boomer_trigger"
|
||||
val Building = "building"
|
||||
val CaptureFlag = "capture_flag"
|
||||
val CaptureFlagSocket = "capture_flag_socket"
|
||||
val CaptureFlagSocket = "llm_socket"
|
||||
val CaptureTerminal = "capture_terminal"
|
||||
val CertTerminal = "cert_terminal"
|
||||
val ChainLashDamager = "chain_lash_damager"
|
||||
|
|
|
|||
|
|
@ -710,12 +710,18 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
super.CancelJammeredStatus(target)
|
||||
//uninitialize implants
|
||||
avatarActor ! AvatarActor.DeinitializeImplants()
|
||||
|
||||
cause.adversarial match {
|
||||
case Some(a) =>
|
||||
damageLog.info(s"DisplayDestroy: ${a.defender} was killed by ${a.attacker}")
|
||||
case _ =>
|
||||
damageLog.info(s"DisplayDestroy: ${player.Name} killed ${player.Sex.pronounObject}self.")
|
||||
}
|
||||
|
||||
// This would normally happen async as part of AvatarAction.Killed, but if it doesn't happen before deleting calling AvatarAction.ObjectDelete on the player the LLU will end up invisible to others if carried
|
||||
// Therefore, queue it up to happen first.
|
||||
events ! AvatarServiceMessage(nameChannel, AvatarAction.DropSpecialItem())
|
||||
|
||||
events ! AvatarServiceMessage(
|
||||
nameChannel,
|
||||
AvatarAction.Killed(player_guid, target.VehicleSeated)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package net.psforever.objects.definition.converter
|
||||
|
||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
import net.psforever.packet.game.objectcreate.{CaptureFlagData, PlacementData}
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
import scala.util.{Success, Try}
|
||||
|
||||
class CaptureFlagConverter extends ObjectCreateConverter[CaptureFlag]() {
|
||||
override def ConstructorData(obj : CaptureFlag) : Try[CaptureFlagData] = {
|
||||
val hackInfo = obj.Owner.asInstanceOf[Building].CaptureTerminal.get.HackedBy.get
|
||||
val millisecondsRemaining = TimeUnit.MILLISECONDS.convert(math.max(0, hackInfo.hackStartTime + hackInfo.hackDuration - System.nanoTime), TimeUnit.NANOSECONDS)
|
||||
|
||||
Success(
|
||||
CaptureFlagData(
|
||||
new PlacementData(obj.Position, obj.Orientation, obj.Velocity),
|
||||
obj.Faction,
|
||||
obj.Owner.asInstanceOf[Building].GUID.guid,
|
||||
obj.Target.GUID.guid,
|
||||
millisecondsRemaining
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package net.psforever.objects.serverobject.llu
|
||||
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, AmenityOwner, Building}
|
||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||
|
||||
/**
|
||||
* This object represents the LLU that gets spawned at a LLU socket when a LLU control console is hacked
|
||||
*/
|
||||
class CaptureFlag(tDef: CaptureFlagDefinition) extends Amenity {
|
||||
def Definition : CaptureFlagDefinition = tDef
|
||||
|
||||
private var target: Building = Building.NoBuilding
|
||||
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||
private var carrier: Option[Player] = None
|
||||
|
||||
def Target: Building = target
|
||||
def Target_=(new_target: Building): Building = {
|
||||
target = new_target
|
||||
target
|
||||
}
|
||||
|
||||
// Since a LLU belongs to a base, but needs to be picked up by the enemy faction we need to be able to override the faction that owns the LLU to the hacker faction
|
||||
override def Faction: PlanetSideEmpire.Value = faction
|
||||
override def Faction_=(new_faction: PlanetSideEmpire.Value): PlanetSideEmpire.Value = {
|
||||
faction = new_faction
|
||||
faction
|
||||
}
|
||||
|
||||
// When the flag is carried by a player, the position returned should be that of the carrier not the flag
|
||||
override def Position: Vector3 = if (Carrier.nonEmpty) {
|
||||
carrier.get.Position
|
||||
} else {
|
||||
Entity.Position
|
||||
}
|
||||
|
||||
def Carrier: Option[Player] = carrier
|
||||
def Carrier_=(new_carrier: Option[Player]) : Option[Player] = {
|
||||
carrier = new_carrier
|
||||
carrier
|
||||
}
|
||||
}
|
||||
|
||||
object CaptureFlag {
|
||||
def apply(tDef: CaptureFlagDefinition): CaptureFlag = {
|
||||
new CaptureFlag(tDef)
|
||||
}
|
||||
|
||||
def Constructor(pos: Vector3, ori: Vector3, target: Building, owner: AmenityOwner, faction: PlanetSideEmpire.Value) : CaptureFlag = {
|
||||
val obj = CaptureFlag(GlobalDefinitions.capture_flag)
|
||||
obj.Position = pos
|
||||
obj.Orientation = ori
|
||||
obj.Target = target
|
||||
obj.Owner = owner
|
||||
obj.Faction = faction
|
||||
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package net.psforever.objects.serverobject.llu
|
||||
|
||||
import net.psforever.objects.serverobject.structures.AmenityDefinition
|
||||
|
||||
/**
|
||||
* The definition for any 'CaptureFlag'
|
||||
* Object Id 157
|
||||
*/
|
||||
class CaptureFlagDefinition extends AmenityDefinition(157) {
|
||||
Name = "capture_flag"
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package net.psforever.objects.serverobject.llu
|
||||
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
|
||||
/**
|
||||
* Represents the LLU sockets found within bases that require LLU hacks.
|
||||
* It is used as a position reference for spawning the LLU in the correct location when the base is hacked
|
||||
* @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||
*/
|
||||
class CaptureFlagSocket(tDef: CaptureFlagSocketDefinition) extends Amenity {
|
||||
def Definition : CaptureFlagSocketDefinition = tDef
|
||||
}
|
||||
|
||||
object CaptureFlagSocket {
|
||||
def apply(tDef: CaptureFlagSocketDefinition) : CaptureFlagSocket = {
|
||||
new CaptureFlagSocket(tDef)
|
||||
}
|
||||
|
||||
def Constructor(pos: Vector3)(id: Int, context: ActorContext) : CaptureFlagSocket = {
|
||||
Constructor(GlobalDefinitions.llm_socket, pos)(id, context)
|
||||
}
|
||||
|
||||
def Constructor(tdef: CaptureFlagSocketDefinition, pos: Vector3)(id: Int, context: ActorContext) : CaptureFlagSocket = {
|
||||
val obj = CaptureFlagSocket(tdef)
|
||||
obj.Position = pos
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package net.psforever.objects.serverobject.llu
|
||||
|
||||
import net.psforever.objects.serverobject.structures.AmenityDefinition
|
||||
|
||||
/**
|
||||
* The definition for any 'CaptureFlagSocket'
|
||||
* Object Id 450
|
||||
*/
|
||||
class CaptureFlagSocketDefinition extends AmenityDefinition(450) {
|
||||
Name = "llm_socket"
|
||||
}
|
||||
|
|
@ -18,4 +18,9 @@ abstract class AmenityOwner extends PlanetSideServerObject {
|
|||
obj.Owner = this
|
||||
amenities
|
||||
}
|
||||
|
||||
def RemoveAmenity(obj: Amenity): List[Amenity] = {
|
||||
amenities = amenities.filterNot(x => x == obj)
|
||||
amenities
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import net.psforever.packet.game.BuildingInfoUpdateMessage
|
|||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, PlanetSideGeneratorState, Vector3}
|
||||
import scalax.collection.{Graph, GraphEdge}
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import net.psforever.objects.serverobject.llu.{CaptureFlag, CaptureFlagSocket}
|
||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
||||
|
||||
class Building(
|
||||
|
|
@ -27,10 +28,6 @@ class Building(
|
|||
private val buildingDefinition: BuildingDefinition
|
||||
) extends AmenityOwner {
|
||||
|
||||
/**
|
||||
* The map_id is the identifier number used in BuildingInfoUpdateMessage. This is the index that the building appears in the MPO file starting from index 1
|
||||
* The GUID is the identifier number used in SetEmpireMessage / Facility hacking / PlanetSideAttributeMessage.
|
||||
*/
|
||||
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||
private var playersInSOI: List[Player] = List.empty
|
||||
private val capitols = List("Thoth", "Voltan", "Neit", "Anguta", "Eisa", "Verica")
|
||||
|
|
@ -43,6 +40,10 @@ class Building(
|
|||
|
||||
def Name: String = name
|
||||
|
||||
/**
|
||||
* The map_id is the identifier number used in BuildingInfoUpdateMessage. This is the index that the building appears in the MPO file starting from index 1
|
||||
* The GUID is the identifier number used in SetEmpireMessage / Facility hacking / PlanetSideAttributeMessage.
|
||||
*/
|
||||
def MapId: Int = map_id
|
||||
|
||||
def IsCapitol: Boolean = capitols.contains(name)
|
||||
|
|
@ -122,6 +123,14 @@ class Building(
|
|||
}
|
||||
}
|
||||
|
||||
def IsCtfBase: Boolean = GetFlagSocket match {
|
||||
case Some(_) => true
|
||||
case _ => false
|
||||
}
|
||||
|
||||
def GetFlagSocket: Option[CaptureFlagSocket] = this.Amenities.find(_.Definition == GlobalDefinitions.llm_socket).asInstanceOf[Option[CaptureFlagSocket]]
|
||||
def GetFlag: Option[CaptureFlag] = this.Amenities.find(_.Definition == GlobalDefinitions.capture_flag).asInstanceOf[Option[CaptureFlag]]
|
||||
|
||||
def HackableAmenities: List[Amenity with Hackable] = {
|
||||
Amenities.filter(x => x.isInstanceOf[Hackable]).map(x => x.asInstanceOf[Amenity with Hackable])
|
||||
}
|
||||
|
|
@ -200,9 +209,11 @@ class Building(
|
|||
// Check this Building is on the lattice first
|
||||
zone.Lattice find this match {
|
||||
case Some(_) =>
|
||||
// todo: generator destruction state
|
||||
val subGraph = Zone.Lattice filter ((b: Building) =>
|
||||
b.Faction == this.Faction && !b.CaptureTerminalIsHacked && b.NtuLevel > 0
|
||||
b.Faction == this.Faction
|
||||
&& !b.CaptureTerminalIsHacked
|
||||
&& b.NtuLevel > 0
|
||||
&& (b.Generator.isEmpty || b.Generator.get.Condition != PlanetSideGeneratorState.Destroyed)
|
||||
)
|
||||
|
||||
var stackedBenefit = 0
|
||||
|
|
@ -226,13 +237,13 @@ class Building(
|
|||
hackingFaction,
|
||||
hackTime,
|
||||
if (ntuLevel > 0) Faction else PlanetSideEmpire.NEUTRAL,
|
||||
0, // Field != 0 will cause malformed packet
|
||||
None,
|
||||
0, // unk1 Field != 0 will cause malformed packet
|
||||
None, // unk1x
|
||||
generatorState,
|
||||
spawnTubesNormal,
|
||||
forceDomeActive,
|
||||
latticeBenefit,
|
||||
48, // cavern benefit
|
||||
if (generatorState != PlanetSideGeneratorState.Destroyed) latticeBenefit else 0,
|
||||
if (generatorState != PlanetSideGeneratorState.Destroyed) 48 else 0, // cavern benefit
|
||||
Nil, // unk4,
|
||||
0, // unk5
|
||||
false, // unk6
|
||||
|
|
|
|||
|
|
@ -531,7 +531,7 @@ object GamePacketOpcode extends Enumeration {
|
|||
case 0xbf => game.ZipLineMessage.decode
|
||||
|
||||
// OPCODES 0xc0-cf
|
||||
case 0xc0 => noDecoder(CaptureFlagUpdateMessage)
|
||||
case 0xc0 => game.CaptureFlagUpdateMessage.decode
|
||||
case 0xc1 => noDecoder(VanuModuleUpdateMessage)
|
||||
case 0xc2 => game.FacilityBenefitShieldChargeRequestMessage.decode
|
||||
case 0xc3 => game.ProximityTerminalUseMessage.decode
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.newcodecs.newcodecs
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import shapeless.{::, HNil}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param zone_number The zone number this packet applies to
|
||||
* @param flagInfoList The list of LLUs/Monolith units for this zone
|
||||
*/
|
||||
final case class CaptureFlagUpdateMessage(zone_number: Int, flagInfoList: List[FlagInfo]) extends PlanetSideGamePacket {
|
||||
type Packet = CaptureFlagUpdateMessage
|
||||
def opcode = GamePacketOpcode.CaptureFlagUpdateMessage
|
||||
def encode = CaptureFlagUpdateMessage.encode(this)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param u1 No effect. Faction ID perhaps?
|
||||
* @param owner_map_id The mapID of the base the LLU belongs to
|
||||
* @param target_map_id The mapID of the base the LLU must be delivered to
|
||||
* @param x X map position
|
||||
* @param y Y map position
|
||||
* @param hack_time_remaining Time remaining on hack - will override BuildingInfoUpdateMessage when displaying hack timer on map base details
|
||||
* @param is_monolith_unit Changes the icon on the map to the monolith unit icon
|
||||
*/
|
||||
final case class FlagInfo(u1: Int, owner_map_id: Int, target_map_id: Int, x: Float, y: Float, hack_time_remaining: Long, is_monolith_unit: Boolean)
|
||||
object FlagInfo extends Marshallable[FlagInfo] {
|
||||
implicit val codec: Codec[FlagInfo] = {
|
||||
(("u1" | uint2L)
|
||||
:: ("owner_map_id" | uint16L)
|
||||
:: ("target_map_id" | uint16L)
|
||||
:: ("u4" | newcodecs.q_float(0.0, 8192.0, 20))
|
||||
:: ("u5" | newcodecs.q_float(0.0, 8192.0, 20))
|
||||
:: ("hack_time_remaining" | uint32L)
|
||||
:: ("is_monolith_unit" | bool))
|
||||
}.as[FlagInfo]
|
||||
}
|
||||
|
||||
object CaptureFlagUpdateMessage extends Marshallable[CaptureFlagUpdateMessage] {
|
||||
implicit val codec: Codec[CaptureFlagUpdateMessage] = (
|
||||
("zone_number" | uint16L)
|
||||
:: ("flagInfoList" | PacketHelpers.listOfNAligned(longL(4), alignment = 0, FlagInfo.codec)) // Maximum of 7 on any map
|
||||
).xmap[CaptureFlagUpdateMessage] (
|
||||
{
|
||||
case zone_number :: flagInfoList :: HNil =>
|
||||
CaptureFlagUpdateMessage(zone_number, flagInfoList)
|
||||
},
|
||||
{
|
||||
case CaptureFlagUpdateMessage(zone_number, flagInfoList) =>
|
||||
zone_number :: flagInfoList :: HNil
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -19,8 +19,11 @@ import scodec.codecs._
|
|||
* 07 - warning: missile lock<br>
|
||||
* 08 - warning: Wasp missile lock<br>
|
||||
* 09 - warning: T-REK lock<br>
|
||||
* 11 - Drop special item e.g. LLU<br>
|
||||
* 12 - sound: base captured fanfare<br>
|
||||
* 14 - prompt: new character basic training<br>
|
||||
* 15 - MAX Deploy<br>
|
||||
* 16 - MAX Undeploy<br>
|
||||
* 22 - message: awarded a cavern capture (updates cavern capture status)<br>
|
||||
* 23 - award a cavern kill<br>
|
||||
* 24 - message: you have been imprinted (updates imprinted status; does it?)<br>
|
||||
|
|
@ -54,7 +57,21 @@ final case class GenericActionMessage(action: Int) extends PlanetSideGamePacket
|
|||
}
|
||||
|
||||
object GenericActionMessage extends Marshallable[GenericActionMessage] {
|
||||
def apply(action: GenericActionEnum.GenericActionEnum): GenericActionMessage = {
|
||||
GenericActionMessage(action.id)
|
||||
}
|
||||
|
||||
implicit val codec: Codec[GenericActionMessage] = (
|
||||
"action" | uint(6)
|
||||
).as[GenericActionMessage]
|
||||
}
|
||||
|
||||
object GenericActionEnum extends Enumeration {
|
||||
type GenericActionEnum = Value
|
||||
|
||||
/** Drop special item e.g. LLU */
|
||||
val DropSpecialItem = Value(11)
|
||||
|
||||
/** Plays the base capture fanfare sound */
|
||||
val BaseCaptureFanfare = Value(12)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,36 +11,38 @@ import shapeless.{::, HNil}
|
|||
/**
|
||||
* Dispatched by the server to enact an effect on some game object.
|
||||
* (Write more some other time.)
|
||||
* @param object_guid the target object
|
||||
* @param code the action code (0-63)
|
||||
* 6 - Deconstructs player
|
||||
* 7 - Start imprinting process (progress bar + character animation)
|
||||
* 8 - Finish imprinting?
|
||||
* 9 - Cloak
|
||||
* 10 - Uncloak
|
||||
* 11 - Deploy capital base shield pole with animation and broadcasts "The capitol force dome at X has been activated"
|
||||
* 12 - Stow capital base shield pole with animation and broadcasts "The capitol force dome at X has been deactivated"
|
||||
* 13 - Deploy capital base shield pole (instantly, unless still in the middle of the stow animation)
|
||||
* 15 - Displays "This facility's generator is under attack!"
|
||||
* 16 - Displays "Generator has Overloaded! Evacuate Generator Room Immediately!"
|
||||
* 17 - Displays "This facility's generator is back on line"
|
||||
* 19 - Cause mines to explode
|
||||
* 20 - Hit flinch? (orig, 82->80)
|
||||
* 21 - Reset build cooldown from using an ACE
|
||||
* 22 - ???? (Has been seen on vehicle pad objects, possibly some sort of reset flag after base faction flip / hack clear?)
|
||||
* 23 - Plays vehicle pad animation moving downwards
|
||||
* 24 - Makes the vehicle bounce slightly. Have seen this in packet captures after taking a vehicle through a warpgate
|
||||
* 27 - Activates the router internal telepad for linking
|
||||
* 28 - Activates the router internal telepad for linking
|
||||
* 29 - Activates the telepad deployable (also used on the router's internal telepad)
|
||||
* 30 - Activates the telepad deployable (also used on the router's internal telepad)
|
||||
* 31 - Animation during router teleportation (source)
|
||||
* 32 - Animation during router teleportation (destination)
|
||||
* 34 - Time until item can be used ?????
|
||||
* 50 - For aircraft - client shows "The bailing mechanism failed! To fix the mechanism, land and repair the vehicle!"
|
||||
* 53 - Put down an FDU
|
||||
* 56 - Sets vehicle or player to be black ops
|
||||
* 57 - Reverts player from black ops
|
||||
* @param object_guid the target object<br/>
|
||||
* @param code the action code (0-63)<br/>
|
||||
* 6 - Deconstructs player<br/>
|
||||
* 7 - Start imprinting process (progress bar + character animation)<br/>
|
||||
* 8 - Finish imprinting?<br/>
|
||||
* 9 - Cloak<br/>
|
||||
* 10 - Uncloak<br/>
|
||||
* 11 - Deploy capital base shield pole with animation and broadcasts "The capitol force dome at X has been activated"<br/>
|
||||
* 12 - Stow capital base shield pole with animation and broadcasts "The capitol force dome at X has been deactivated"<br/>
|
||||
* 13 - Deploy capital base shield pole (instantly, unless still in the middle of the stow animation)<br/>
|
||||
* 14 - Changes capture console to say "Facility hacked by the <Faction> LLU has been spawned." when looked at<br/>
|
||||
* 15 - Displays "This facility's generator is under attack!"<br/>
|
||||
* 16 - Displays "Generator has Overloaded! Evacuate Generator Room Immediately!"<br/>
|
||||
* 17 - Displays "This facility's generator is back on line"<br/>
|
||||
* 19 - Cause mines to explode<br/>
|
||||
* 20 - Hit flinch? (orig, 82->80)<br/>
|
||||
* 21 - Reset build cooldown from using an ACE<br/>
|
||||
* 22 - ???? (Has been seen on vehicle pad objects, possibly some sort of reset flag after base faction flip / hack clear?)<br/>
|
||||
* 23 - Plays vehicle pad animation moving downwards<br/>
|
||||
* 24 - Makes the vehicle bounce slightly. Have seen this in packet captures after taking a vehicle through a warpgate<br/>
|
||||
* 27 - Activates the router internal telepad for linking<br/>
|
||||
* 28 - Activates the router internal telepad for linking<br/>
|
||||
* 29 - Activates the telepad deployable (also used on the router's internal telepad)<br/>
|
||||
* 30 - Activates the telepad deployable (also used on the router's internal telepad)<br/>
|
||||
* 31 - Animation during router teleportation (source)<br/>
|
||||
* 32 - Animation during router teleportation (destination)<br/>
|
||||
* 34 - Time until item can be used ?????<br/>
|
||||
* 50 - For aircraft - client shows "The bailing mechanism failed! To fix the mechanism, land and repair the vehicle!"<br/>
|
||||
* 53 - Put down an FDU<br/>
|
||||
* 56 - Sets vehicle or player to be black ops<br/>
|
||||
* 57 - Reverts player from black ops<br/>
|
||||
* @see GenericObjectActionEnum
|
||||
*/
|
||||
final case class GenericObjectActionMessage(object_guid: PlanetSideGUID, code: Int) extends PlanetSideGamePacket {
|
||||
type Packet = GenericObjectActionMessage
|
||||
|
|
@ -49,6 +51,10 @@ final case class GenericObjectActionMessage(object_guid: PlanetSideGUID, code: I
|
|||
}
|
||||
|
||||
object GenericObjectActionMessage extends Marshallable[GenericObjectActionMessage] {
|
||||
def apply(object_guid: PlanetSideGUID, code: GenericObjectActionEnum.GenericObjectActionEnum): GenericObjectActionMessage = {
|
||||
GenericObjectActionMessage(object_guid, code.id)
|
||||
}
|
||||
|
||||
implicit val codec: Codec[GenericObjectActionMessage] = (
|
||||
("object_guid" | PlanetSideGUID.codec) ::
|
||||
("code" | uint(bits = 6)) ::
|
||||
|
|
@ -64,3 +70,12 @@ object GenericObjectActionMessage extends Marshallable[GenericObjectActionMessag
|
|||
}
|
||||
)
|
||||
}
|
||||
|
||||
object GenericObjectActionEnum extends Enumeration {
|
||||
type GenericObjectActionEnum = Value
|
||||
|
||||
/** <b>Effect:</b> Capture console displays "Facility hacked by the <Faction> LLU has been spawned." when looked at<br>
|
||||
* <b>Target</b>: CaptureTerminal
|
||||
*/
|
||||
val FlagSpawned = Value(14)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import scodec.codecs._
|
|||
* `0x84` - 4 - knife holster<br>
|
||||
* `0x86` - 6 - grid (1,1)<br>
|
||||
* `0x00FA` - 250 - is a special dest/extra code that "attaches the item to the player's cursor"
|
||||
* `0x00FC` - 252 - special item slot e.g. LLU (Possibly also cavern modules)
|
||||
* @param parent_guid the parent object
|
||||
* @param child_guid the child object
|
||||
* @param slot a codified location within the parent object's inventory;
|
||||
|
|
|
|||
|
|
@ -144,8 +144,8 @@ import scodec.codecs._
|
|||
* `43 - Info on avatar name : 0 = Nothing, 1 = "(LD)" message`<br>
|
||||
* `45 - NTU charge bar 0-10, 5 = 50% full. Seems to apply to both ANT and NTU Silo (possibly siphons?)`<br>
|
||||
* `46 - Sends "Generator damage is at a critical level!" message`
|
||||
* `47 - Sets base NTU level to CRITICAL. MUST use base MapId not base GUID`<br>
|
||||
* `48 - Set to 1 to send base power loss message & turns on red warning lights throughout base. MUST use base MapId not base GUID`?<br>
|
||||
* `47 - Sets base NTU level to CRITICAL.`<br>
|
||||
* `48 - Set to 1 to send base power loss message & turns on red warning lights throughout base.<br>
|
||||
* `49 - Vehicle texture effects state? (>0 turns on ANT panel glow or ntu silo panel glow + orbs) (bit?)`<br>
|
||||
* `52 - Vehicle particle effects? (>0 turns on orbs going towards ANT. Doesn't affect silo) (bit?)`<br>
|
||||
* `53 - LFS. Value is 1 to flag LFS`<br>
|
||||
|
|
@ -161,7 +161,7 @@ import scodec.codecs._
|
|||
* `55 - "Someone is attempting to Heal you". Value is 1`<br>
|
||||
* `56 - "Someone is attempting to Repair you". Value is 1`<br>
|
||||
* `64 - ????? related to using router telepads`
|
||||
* `67 - Enables base shields (from cavern module/lock). MUST use base MapId not GUID`<br>
|
||||
* `67 - Enables base shields (from cavern module/lock)`<br>
|
||||
* `73 - "You are locked into the Core Beam. Charging your Module now.". Value is 1 to active`<br>
|
||||
* `77 - Cavern Facility Captures. Value is the number of captures`<br>
|
||||
* `78 - Cavern Kills. Value is the number of kills`<br>
|
||||
|
|
|
|||
|
|
@ -16,19 +16,18 @@ import shapeless.{::, HNil}
|
|||
* Whenever an applicable player is nearby, that client will rapidly fire off `ItemUseMessage` packets to the server.
|
||||
* The capture flag will be picked-up by the player and stored in a special slot that is not part of their inventory.
|
||||
* A special dropping keybind has been prepared to relinquish the capture flag back to the game world.
|
||||
* @param pos the position + orientation + velocity of the LLU where it is dropped/spawned
|
||||
* @param faction the empire whose players may interact with this capture flag
|
||||
* @param unk1 na
|
||||
* @param unk2 na
|
||||
* @param unk3 na
|
||||
* @param unk4 na
|
||||
* @param owningBaseGuid The GUID of the base that this LLU belongs to
|
||||
* @param targetBaseGuid The GUID of the base that this LLU must be taken to
|
||||
* @param milliseconds_remaining The number of milliseconds left on the timer for this LLU - should match the CC timer
|
||||
*/
|
||||
final case class CaptureFlagData(
|
||||
pos: PlacementData,
|
||||
faction: PlanetSideEmpire.Value,
|
||||
unk1: Int,
|
||||
unk2: Int,
|
||||
unk3: Int,
|
||||
unk4: Int
|
||||
owningBaseGuid : Int,
|
||||
targetBaseGuid : Int,
|
||||
milliseconds_remaining : Long
|
||||
) extends ConstructorData {
|
||||
override def bitsize: Long = 88L + pos.bitsize
|
||||
}
|
||||
|
|
@ -40,24 +39,23 @@ object CaptureFlagData extends Marshallable[CaptureFlagData] {
|
|||
bool ::
|
||||
uint4L ::
|
||||
uint16L ::
|
||||
("unk1" | uint8L) ::
|
||||
("owningBaseGuid" | uint8L) ::
|
||||
uint8L ::
|
||||
("unk2" | uint8L) ::
|
||||
("targetBaseGuid" | uint8L) ::
|
||||
uint8L ::
|
||||
("unk3" | uint16L) :: //probably a PlanetSideGUID
|
||||
("unk4" | uint8L) ::
|
||||
uint(9)
|
||||
("milliseconds_remaining" | uint32L) ::
|
||||
uint(1)
|
||||
).exmap[CaptureFlagData](
|
||||
{
|
||||
case pos :: fac :: false :: 4 :: 0 :: unk1 :: 0 :: unk2 :: 0 :: unk3 :: unk4 :: 0 :: HNil =>
|
||||
Attempt.Successful(CaptureFlagData(pos, fac, unk1, unk2, unk3, unk4))
|
||||
case pos :: faction :: false :: 4 :: 0 :: owningBaseGuid :: 0 :: targetBaseGuid :: 0 :: milliseconds_remaining :: 0 :: HNil =>
|
||||
Attempt.Successful(CaptureFlagData(pos, faction, owningBaseGuid, targetBaseGuid, milliseconds_remaining))
|
||||
|
||||
case data =>
|
||||
Attempt.failure(Err(s"invalid capture flag data format - $data"))
|
||||
},
|
||||
{
|
||||
case CaptureFlagData(pos, fac, unk1, unk2, unk3, unk4) =>
|
||||
Attempt.successful(pos :: fac :: false :: 4 :: 0 :: unk1 :: 0 :: unk2 :: 0 :: unk3 :: unk4 :: 0 :: HNil)
|
||||
case CaptureFlagData(pos, faction, owningBaseGuid, targetBaseGuid, milliseconds_remaining) =>
|
||||
Attempt.successful(pos :: faction :: false :: 4 :: 0 :: owningBaseGuid :: 0 :: targetBaseGuid :: 0 :: milliseconds_remaining :: 0 :: HNil)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -408,6 +408,9 @@ class AvatarService(zone: Zone) extends Actor {
|
|||
)
|
||||
)
|
||||
|
||||
case AvatarAction.DropSpecialItem() =>
|
||||
AvatarEvents.publish(AvatarServiceResponse(s"/$forChannel/Avatar", Service.defaultPlayerGUID, AvatarResponse.DropSpecialItem()))
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ object AvatarAction {
|
|||
inventory: List[InventoryItem],
|
||||
drop: List[InventoryItem]
|
||||
) extends Action
|
||||
final case class DropSpecialItem() extends Action
|
||||
|
||||
final case class TeardownConnection() extends Action
|
||||
// final case class PlayerStateShift(killer : PlanetSideGUID, victim : PlanetSideGUID) extends Action
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ object AvatarResponse {
|
|||
inventory: List[InventoryItem],
|
||||
drop: List[InventoryItem]
|
||||
) extends Response
|
||||
final case class DropSpecialItem() extends Response
|
||||
|
||||
final case class TeardownConnection() extends Response
|
||||
// final case class PlayerStateShift(itemID : PlanetSideGUID) extends Response
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package net.psforever.services.galaxy
|
|||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.BuildingInfoUpdateMessage
|
||||
import net.psforever.packet.game.{BuildingInfoUpdateMessage, FlagInfo}
|
||||
import net.psforever.services.{GenericEventBus, Service}
|
||||
|
||||
class GalaxyService extends Actor {
|
||||
|
|
@ -41,6 +41,11 @@ class GalaxyService extends Actor {
|
|||
GalaxyServiceResponse(s"/Galaxy", GalaxyResponse.MapUpdate(msg))
|
||||
)
|
||||
|
||||
case GalaxyAction.FlagMapUpdate(msg) =>
|
||||
GalaxyEvents.publish(
|
||||
GalaxyServiceResponse(s"/Galaxy", GalaxyResponse.FlagMapUpdate(msg))
|
||||
)
|
||||
|
||||
case GalaxyAction.TransferPassenger(_, temp_channel, vehicle, vehicle_to_delete, manifest) =>
|
||||
GalaxyEvents.publish(
|
||||
GalaxyServiceResponse(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package net.psforever.services.galaxy
|
|||
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.vehicles.VehicleManifest
|
||||
import net.psforever.packet.game.BuildingInfoUpdateMessage
|
||||
import net.psforever.packet.game.{BuildingInfoUpdateMessage, CaptureFlagUpdateMessage, FlagInfo}
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
|
||||
final case class GalaxyServiceMessage(forChannel: String, actionMessage: GalaxyAction.Action)
|
||||
|
|
@ -16,6 +16,7 @@ object GalaxyAction {
|
|||
trait Action
|
||||
|
||||
final case class MapUpdate(msg: BuildingInfoUpdateMessage) extends Action
|
||||
final case class FlagMapUpdate(msg: CaptureFlagUpdateMessage) extends Action
|
||||
|
||||
final case class TransferPassenger(
|
||||
player_guid: PlanetSideGUID,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package net.psforever.services.galaxy
|
|||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.vehicles.VehicleManifest
|
||||
import net.psforever.objects.zones.HotSpotInfo
|
||||
import net.psforever.packet.game.BuildingInfoUpdateMessage
|
||||
import net.psforever.packet.game.{BuildingInfoUpdateMessage, CaptureFlagUpdateMessage, FlagInfo}
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
import net.psforever.services.GenericEventBusMsg
|
||||
|
||||
|
|
@ -16,6 +16,8 @@ object GalaxyResponse {
|
|||
|
||||
final case class HotSpotUpdate(zone_id: Int, priority: Int, host_spot_info: List[HotSpotInfo]) extends Response
|
||||
final case class MapUpdate(msg: BuildingInfoUpdateMessage) extends Response
|
||||
final case class FlagMapUpdate(msg: CaptureFlagUpdateMessage) extends Response
|
||||
|
||||
|
||||
final case class TransferPassenger(
|
||||
temp_channel: String,
|
||||
|
|
|
|||
|
|
@ -2,27 +2,26 @@
|
|||
package net.psforever.services.local
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.objects._
|
||||
import net.psforever.packet.game.{TriggeredEffect, TriggeredEffectLocation}
|
||||
import net.psforever.objects.vehicles.{Utility, UtilityType}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.types.{PlanetSideGUID, Vector3}
|
||||
import net.psforever.services.local.support._
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.{TriggeredEffect, TriggeredEffectLocation}
|
||||
import net.psforever.services.local.support.{CaptureFlagManager, _}
|
||||
import net.psforever.services.support.SupportActor
|
||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
import net.psforever.services.{GenericEventBus, RemoverActor, Service}
|
||||
import net.psforever.types.{PlanetSideGUID, Vector3}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import net.psforever.objects.vehicles.{Utility, UtilityType}
|
||||
import net.psforever.services.support.SupportActor
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
import scala.concurrent.duration.{Duration, _}
|
||||
|
||||
class LocalService(zone: Zone) extends Actor {
|
||||
private val doorCloser = context.actorOf(Props[DoorCloseActor](), s"${zone.id}-local-door-closer")
|
||||
private val hackClearer = context.actorOf(Props[HackClearActor](), s"${zone.id}-local-hack-clearer")
|
||||
private val hackCapturer = context.actorOf(Props[HackCaptureActor](), s"${zone.id}-local-hack-capturer")
|
||||
private val hackCapturer = context.actorOf(Props(classOf[HackCaptureActor], zone.tasks), s"${zone.id}-local-hack-capturer")
|
||||
private val captureFlagManager = context.actorOf(Props(classOf[CaptureFlagManager], zone.tasks, zone), s"${zone.id}-local-capture-flag-manager")
|
||||
private val engineer = context.actorOf(Props(classOf[DeployableRemover], zone.tasks), s"${zone.id}-deployable-remover-agent")
|
||||
private val teleportDeployment: ActorRef =
|
||||
context.actorOf(Props[RouterTelepadActivation](), s"${zone.id}-telepad-activate-agent")
|
||||
|
|
@ -93,10 +92,43 @@ class LocalService(zone: Zone) extends Actor {
|
|||
)
|
||||
case LocalAction.ClearTemporaryHack(_, target) =>
|
||||
hackClearer ! HackClearActor.ObjectIsResecured(target)
|
||||
|
||||
case LocalAction.ResecureCaptureTerminal(target) =>
|
||||
hackCapturer ! HackCaptureActor.ResecureCaptureTerminal(target, zone)
|
||||
case LocalAction.StartCaptureTerminalHack(target) =>
|
||||
hackCapturer ! HackCaptureActor.StartCaptureTerminalHack(target, zone, 0, 8L)
|
||||
case LocalAction.LluCaptured(llu) =>
|
||||
hackCapturer ! HackCaptureActor.FlagCaptured(llu)
|
||||
|
||||
case LocalAction.LluSpawned(player_guid, llu) =>
|
||||
// Forward to all clients to create object locally
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
player_guid,
|
||||
LocalResponse.LluSpawned(llu)
|
||||
)
|
||||
)
|
||||
|
||||
case LocalAction.LluDespawned(player_guid, llu) =>
|
||||
// Forward to all clients to destroy object locally
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
player_guid,
|
||||
LocalResponse.LluDespawned(llu)
|
||||
)
|
||||
)
|
||||
|
||||
case LocalAction.SendPacket(packet) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
PlanetSideGUID(-1),
|
||||
LocalResponse.SendPacket(packet)
|
||||
)
|
||||
)
|
||||
|
||||
case LocalAction.SendPlanetsideAttributeMessage(player_guid, target_guid, attribute_number, attribute_value) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
|
|
@ -105,6 +137,34 @@ class LocalService(zone: Zone) extends Actor {
|
|||
LocalResponse.SendPlanetsideAttributeMessage(target_guid, attribute_number, attribute_value)
|
||||
)
|
||||
)
|
||||
|
||||
case LocalAction.SendGenericObjectActionMessage(player_guid, target_guid, action_number) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
player_guid,
|
||||
LocalResponse.SendGenericObjectActionMessage(target_guid, action_number)
|
||||
)
|
||||
)
|
||||
|
||||
case LocalAction.SendChatMsg(player_guid, msg) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
player_guid,
|
||||
LocalResponse.SendChatMsg(msg)
|
||||
)
|
||||
)
|
||||
|
||||
case LocalAction.SendGenericActionMessage(player_guid, action_number) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
player_guid,
|
||||
LocalResponse.SendGenericActionMessage(action_number)
|
||||
)
|
||||
)
|
||||
|
||||
case LocalAction.RouterTelepadTransport(player_guid, passenger_guid, src_guid, dest_guid) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
|
|
@ -357,6 +417,16 @@ class LocalService(zone: Zone) extends Actor {
|
|||
val cause = damage_func(target)
|
||||
sender() ! Vitality.DamageResolution(target, cause)
|
||||
|
||||
// Forward all CaptureFlagManager messages
|
||||
case msg @
|
||||
(CaptureFlagManager.SpawnCaptureFlag(_, _, _)
|
||||
| CaptureFlagManager.PickupFlag(_, _)
|
||||
| CaptureFlagManager.DropFlag(_)
|
||||
| CaptureFlagManager.Captured(_)
|
||||
| CaptureFlagManager.Lost(_, _)
|
||||
| CaptureFlagManager) =>
|
||||
captureFlagManager.forward(msg)
|
||||
|
||||
case msg =>
|
||||
log.warn(s"Unhandled message $msg from ${sender()}")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.services.local
|
||||
|
||||
import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle}
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
||||
import net.psforever.objects.vehicles.Utility
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
||||
import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle}
|
||||
import net.psforever.packet.PlanetSideGamePacket
|
||||
import net.psforever.packet.game.{DeployableInfo, DeploymentAction, TriggeredSound}
|
||||
import net.psforever.packet.game.GenericActionEnum.GenericActionEnum
|
||||
import net.psforever.packet.game.GenericObjectActionEnum.GenericObjectActionEnum
|
||||
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
||||
import net.psforever.packet.game.{ChatMsg, DeployableInfo, DeploymentAction, TriggeredSound}
|
||||
import net.psforever.services.hart.HartTimer.OrbitalShuttleEvent
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
|
||||
|
||||
|
|
@ -49,14 +52,37 @@ object LocalAction {
|
|||
) extends Action
|
||||
final case class ClearTemporaryHack(player_guid: PlanetSideGUID, target: PlanetSideServerObject with Hackable)
|
||||
extends Action
|
||||
|
||||
final case class ResecureCaptureTerminal(target: CaptureTerminal) extends Action
|
||||
final case class StartCaptureTerminalHack(target: CaptureTerminal) extends Action
|
||||
final case class LluCaptured(llu: CaptureFlag) extends Action
|
||||
final case class LluSpawned(player_guid: PlanetSideGUID, llu: CaptureFlag) extends Action
|
||||
final case class LluDespawned(player_guid: PlanetSideGUID, llu: CaptureFlag) extends Action
|
||||
|
||||
final case class SendPacket(packet: PlanetSideGamePacket) extends Action
|
||||
final case class SendPlanetsideAttributeMessage(
|
||||
player_guid: PlanetSideGUID,
|
||||
target: PlanetSideGUID,
|
||||
attribute_number: PlanetsideAttributeEnum,
|
||||
attribute_value: Long
|
||||
) extends Action
|
||||
|
||||
final case class SendGenericObjectActionMessage(
|
||||
player_guid: PlanetSideGUID,
|
||||
target: PlanetSideGUID,
|
||||
action_number: GenericObjectActionEnum
|
||||
) extends Action
|
||||
|
||||
final case class SendChatMsg(
|
||||
player_guid: PlanetSideGUID,
|
||||
msg: ChatMsg
|
||||
) extends Action
|
||||
|
||||
final case class SendGenericActionMessage(
|
||||
player_guid: PlanetSideGUID,
|
||||
action_number: GenericActionEnum
|
||||
) extends Action
|
||||
|
||||
final case class RouterTelepadTransport(
|
||||
player_guid: PlanetSideGUID,
|
||||
passenger_guid: PlanetSideGUID,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,13 @@ package net.psforever.services.local
|
|||
|
||||
import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle}
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
||||
import net.psforever.objects.serverobject.structures.{AmenityOwner, Building}
|
||||
import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
|
||||
import net.psforever.objects.vehicles.Utility
|
||||
import net.psforever.packet.PlanetSideGamePacket
|
||||
import net.psforever.packet.game.GenericActionEnum.GenericActionEnum
|
||||
import net.psforever.packet.game.GenericObjectActionEnum.GenericObjectActionEnum
|
||||
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
||||
import net.psforever.packet.PlanetSideGamePacket
|
||||
import net.psforever.packet.game._
|
||||
|
|
@ -33,8 +38,18 @@ object LocalResponse {
|
|||
) extends Response
|
||||
final case class SendHackMessageHackCleared(target_guid: PlanetSideGUID, unk1: Long, unk2: Long) extends Response
|
||||
final case class HackObject(target_guid: PlanetSideGUID, unk1: Long, unk2: Long) extends Response
|
||||
|
||||
final case class SendPacket(packet: PlanetSideGamePacket) extends Response
|
||||
final case class SendPlanetsideAttributeMessage(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long)
|
||||
extends Response
|
||||
final case class SendGenericObjectActionMessage(target_guid: PlanetSideGUID, action_number: GenericObjectActionEnum)
|
||||
extends Response
|
||||
final case class SendChatMsg(msg: ChatMsg) extends Response
|
||||
final case class SendGenericActionMessage(action_num: GenericActionEnum) extends Response
|
||||
|
||||
final case class LluSpawned(llu: CaptureFlag) extends Response
|
||||
final case class LluDespawned(llu: CaptureFlag) extends Response
|
||||
|
||||
final case class ObjectDelete(item_guid: PlanetSideGUID, unk: Int) extends Response
|
||||
final case class ProximityTerminalAction(terminal: Terminal with ProximityUnit, target: PlanetSideGameObject)
|
||||
extends Response
|
||||
|
|
|
|||
|
|
@ -0,0 +1,282 @@
|
|||
package net.psforever.services.local.support
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||
import net.psforever.objects.{Default, Player}
|
||||
import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver}
|
||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.services.ServiceManager
|
||||
import net.psforever.services.ServiceManager.{Lookup, LookupResult}
|
||||
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
|
||||
import net.psforever.services.local.support.CaptureFlagLostReasonEnum.CaptureFlagLostReasonEnum
|
||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGUID, Vector3}
|
||||
|
||||
import scala.concurrent.duration.DurationInt
|
||||
import scala.util.Success
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for handling capture flag related lifecycles
|
||||
* @param taskResolver A reference to a zone's task resolver actor
|
||||
*/
|
||||
class CaptureFlagManager(val taskResolver: ActorRef, zone: Zone) extends Actor{
|
||||
private[this] val log = org.log4s.getLogger(self.path.name)
|
||||
|
||||
var galaxyService: ActorRef = ActorRef.noSender
|
||||
|
||||
private var mapUpdateTick: Cancellable = Default.Cancellable
|
||||
|
||||
/** An internally tracked list of current flags, to avoid querying AmenityOwners each second for flag lookups */
|
||||
private var flags: List[CaptureFlag] = Nil
|
||||
|
||||
private def TrackFlag(flag: CaptureFlag): Unit = {
|
||||
flag.Owner.Amenities = flag
|
||||
flags = flags :+ flag
|
||||
|
||||
if (mapUpdateTick.isCancelled) {
|
||||
// Start sending map updates periodically
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
mapUpdateTick = context.system.scheduler.scheduleAtFixedRate(0 seconds, 1 second, self, CaptureFlagManager.MapUpdate())
|
||||
}
|
||||
}
|
||||
|
||||
private def UntrackFlag(flag: CaptureFlag): Unit = {
|
||||
flag.Owner.RemoveAmenity(flag)
|
||||
flags = flags.filterNot(x => x == flag)
|
||||
|
||||
if (flags.isEmpty) {
|
||||
mapUpdateTick.cancel()
|
||||
|
||||
// Send one final map update to clear the last flag from the map
|
||||
self ! CaptureFlagManager.MapUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
val serviceManager = ServiceManager.serviceManager
|
||||
serviceManager ! Lookup("galaxy")
|
||||
|
||||
def receive: Receive = {
|
||||
case LookupResult("galaxy", endpoint) =>
|
||||
galaxyService = endpoint
|
||||
|
||||
case CaptureFlagManager.MapUpdate() =>
|
||||
val flagInfo = flags.map(flag =>
|
||||
FlagInfo(
|
||||
u1 = 0,
|
||||
owner_map_id = flag.Owner.asInstanceOf[Building].MapId,
|
||||
target_map_id = flag.Target.MapId,
|
||||
x = flag.Position.x,
|
||||
y = flag.Position.y,
|
||||
hack_time_remaining = flag.Owner.asInstanceOf[Building].infoUpdateMessage().hack_time_remaining,
|
||||
is_monolith_unit = false
|
||||
)
|
||||
)
|
||||
|
||||
galaxyService ! GalaxyServiceMessage(GalaxyAction.FlagMapUpdate(CaptureFlagUpdateMessage(zone.Number, flagInfo)))
|
||||
|
||||
case CaptureFlagManager.SpawnCaptureFlag(capture_terminal, target, hackingFaction) =>
|
||||
val zone = capture_terminal.Zone
|
||||
val socket = capture_terminal.Owner.asInstanceOf[Building].GetFlagSocket.get
|
||||
|
||||
// Override CC message when looked at
|
||||
zone.LocalEvents ! LocalServiceMessage(
|
||||
zone.id,
|
||||
LocalAction.SendGenericObjectActionMessage(
|
||||
PlanetSideGUID(-1),
|
||||
capture_terminal.GUID,
|
||||
GenericObjectActionEnum.FlagSpawned
|
||||
)
|
||||
)
|
||||
|
||||
// Register LLU object create task and callback to create on clients
|
||||
val flag: CaptureFlag = CaptureFlag.Constructor(
|
||||
Vector3(socket.Position.x, socket.Position.y, socket.Position.z - 1),
|
||||
socket.Orientation,
|
||||
target,
|
||||
socket.Owner,
|
||||
hackingFaction
|
||||
)
|
||||
|
||||
// Add the flag as an amenity and track it internally
|
||||
TrackFlag(flag)
|
||||
|
||||
taskResolver ! CallBackForTask(
|
||||
TaskResolver.GiveTask(GUIDTask.RegisterObjectTask(flag)(socket.Zone.GUID).task),
|
||||
socket.Zone.LocalEvents,
|
||||
LocalServiceMessage(
|
||||
socket.Zone.id,
|
||||
LocalAction.LluSpawned(PlanetSideGUID(-1), flag)
|
||||
)
|
||||
)
|
||||
|
||||
// Broadcast chat message for LLU spawn
|
||||
val owner = flag.Owner.asInstanceOf[Building]
|
||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_FlagSpawned(owner, flag.Target))
|
||||
|
||||
case CaptureFlagManager.Captured(flag: CaptureFlag) =>
|
||||
// Trigger Install sound
|
||||
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUInstall, flag.Target.CaptureTerminal.get.Position, 20, 0.8000001f))
|
||||
|
||||
// Broadcast capture chat message
|
||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_Success(flag.Carrier.get, flag.Owner.asInstanceOf[Building].Name))
|
||||
|
||||
// Despawn flag
|
||||
HandleFlagDespawn(flag)
|
||||
|
||||
case CaptureFlagManager.Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) =>
|
||||
val message = reason match {
|
||||
case CaptureFlagLostReasonEnum.Resecured =>
|
||||
CaptureFlagChatMessageStrings.CTF_Failed_SourceResecured(flag.Owner.asInstanceOf[Building])
|
||||
case CaptureFlagLostReasonEnum.TimedOut =>
|
||||
CaptureFlagChatMessageStrings.CTF_Failed_TimedOut(flag.Owner.asInstanceOf[Building].Name, flag.Target)
|
||||
}
|
||||
|
||||
ChatBroadcast(flag.Zone, message)
|
||||
|
||||
HandleFlagDespawn(flag)
|
||||
|
||||
case CaptureFlagManager.PickupFlag(flag: CaptureFlag, player: Player) =>
|
||||
val continent = flag.Zone
|
||||
|
||||
flag.Carrier = Some(player)
|
||||
|
||||
continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.SendPacket(ObjectAttachMessage(player.GUID, flag.GUID, 252)))
|
||||
continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUPickup, player.Position, 15, volume = 0.8f))
|
||||
|
||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_FlagPickedUp(player, flag.Owner.asInstanceOf[Building].Name), fanfare = false)
|
||||
|
||||
case CaptureFlagManager.DropFlag(flag: CaptureFlag) =>
|
||||
flag.Carrier match {
|
||||
case Some(player: Player) =>
|
||||
// Set the flag position to where the player is that dropped it
|
||||
flag.Position = player.Position
|
||||
|
||||
// Remove attached player from flag
|
||||
flag.Carrier = None
|
||||
|
||||
// Send drop packet
|
||||
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.SendPacket(ObjectDetachMessage(player.GUID, flag.GUID, player.Position, 0, 0, 0)))
|
||||
|
||||
// Send dropped chat message
|
||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_FlagDropped(player, flag.Owner.asInstanceOf[Building].Name), fanfare = false)
|
||||
|
||||
case None =>
|
||||
log.warn("Tried to drop flag but flag has no carrier")
|
||||
}
|
||||
|
||||
case _ =>
|
||||
log.warn("Received unhandled message");
|
||||
}
|
||||
|
||||
private def HandleFlagDespawn(flag: CaptureFlag): Unit = {
|
||||
// Unregister LLU from clients,
|
||||
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.LluDespawned(PlanetSideGUID(-1), flag))
|
||||
|
||||
// Then unregister it from the GUID pool
|
||||
taskResolver ! TaskResolver.GiveTask(GUIDTask.UnregisterObjectTask(flag)(flag.Zone.GUID).task)
|
||||
|
||||
// Remove the flag as an amenity
|
||||
UntrackFlag(flag)
|
||||
}
|
||||
|
||||
private def ChatBroadcast(zone: Zone, message: String, fanfare: Boolean = true): Unit = {
|
||||
val messageType: ChatMessageType = if (fanfare) {
|
||||
ChatMessageType.UNK_223
|
||||
} else {
|
||||
ChatMessageType.UNK_229
|
||||
}
|
||||
|
||||
zone.LocalEvents ! LocalServiceMessage(
|
||||
zone.id,
|
||||
LocalAction.SendChatMsg(
|
||||
PlanetSideGUID(-1),
|
||||
ChatMsg(messageType, wideContents = false, "", message, None)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Todo: Duplicate from SessionActor. Make common.
|
||||
def CallBackForTask(task: TaskResolver.GiveTask, sendTo: ActorRef, pass: Any): TaskResolver.GiveTask = {
|
||||
TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
private val localDesc = task.task.Description
|
||||
private val destination = sendTo
|
||||
private val passMsg = pass
|
||||
|
||||
override def Description: String = s"callback for tasking $localDesc"
|
||||
|
||||
def Execute(resolver: ActorRef): Unit = {
|
||||
destination ! passMsg
|
||||
resolver ! Success(this)
|
||||
}
|
||||
},
|
||||
List(task)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object CaptureFlagManager {
|
||||
final case class SpawnCaptureFlag(capture_terminal: CaptureTerminal, target: Building, hackingFaction: PlanetSideEmpire.Value)
|
||||
final case class PickupFlag(flag: CaptureFlag, player: Player)
|
||||
final case class DropFlag(flag: CaptureFlag)
|
||||
final case class Captured(flag: CaptureFlag)
|
||||
final case class Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum)
|
||||
final case class MapUpdate()
|
||||
}
|
||||
|
||||
object CaptureFlagChatMessageStrings {
|
||||
/*
|
||||
@CTF_Failed_TargetLost=%1's LLU target facility %2 was lost!\nHack canceled!
|
||||
@CTF_Failed_FlagLost=The %1 lost %2's LLU!\nHack canceled!
|
||||
@CTF_Warning_Carrier=%1 of the %2 has %3's LLU.\nIt must be taken to %4 within %5 minutes!
|
||||
@CTF_Warning_NoCarrier=%1's LLU is in the field.\nThe %2 must take it to %3 within %4 minutes!
|
||||
@CTF_Warning_Carrier1Min=%1 of the %2 has %3's LLU.\nIt must be taken to %4 within the next minute!
|
||||
@CTF_Warning_NoCarrier1Min=%1's LLU is in the field.\nThe %2 must take it to %3 within the next minute!
|
||||
*/
|
||||
|
||||
// @CTF_Success=%1 captured %2's LLU for the %3!
|
||||
/** {player.Name} captured {owner_name}'s LLU for the {player.Faction}! */
|
||||
def CTF_Success(player: Player, owner_name: String): String = s"@CTF_Success^${player.Name}~^@$owner_name~^@${GetFactionString(player.Faction)}~"
|
||||
|
||||
// @CTF_Failed_TimedOut=The %1 failed to deliver %2's LLU to %3 in time!\nHack canceled!
|
||||
/** The {target.Faction} failed to deliver {owner_name}'s LLU to {target.Name} in time!\nHack canceled! */
|
||||
def CTF_Failed_TimedOut(owner_name: String, target: Building): String = s"@CTF_Failed_TimedOut^@${GetFactionString(target.Faction)}~^@$owner_name~^@${target.Name}~"
|
||||
|
||||
// @CTF_Failed_SourceResecured=The %1 resecured %2!\nThe LLU was lost!
|
||||
/** The {owner.Faction} resecured {owner.Name}!\nThe LLU was lost! */
|
||||
def CTF_Failed_SourceResecured(owner: Building): String = s"@CTF_Failed_SourceResecured^@${CaptureFlagChatMessageStrings.GetFactionString(owner.Faction)}~^@${owner.Name}~"
|
||||
|
||||
|
||||
|
||||
// @CTF_FlagSpawned=%1 %2 has spawned a LLU.\nIt must be taken to %3 %4's Control Console within %5 minutes or the hack will fail!
|
||||
/** {facilityType} {facilityName} has spawned a LLU.\nIt must be taken to {targetFacilityType} {targetFacilityName}'s Control Console within 15 minutes or the hack will fail! */
|
||||
def CTF_FlagSpawned(owner: Building, target: Building): String = s"@CTF_FlagSpawned^@${owner.Definition.Name}~^@${owner.Name}~^@${target.Definition.Name}~^@${target.Name}~^15~"
|
||||
|
||||
|
||||
// @CTF_FlagPickedUp=%1 of the %2 picked up %3's LLU
|
||||
/** {playerName} of the {faction} picked up {facilityName}'s LLU */
|
||||
def CTF_FlagPickedUp(player: Player, owner_name: String): String = s"@CTF_FlagPickedUp^${player.Name}~^@${CaptureFlagChatMessageStrings.GetFactionString(player.Faction)}~^@$owner_name~"
|
||||
|
||||
// @CTF_FlagDropped=%1 of the %2 dropped %3's LLU
|
||||
/** {playerName} of the {faction} dropped {facilityName}'s LLU */
|
||||
def CTF_FlagDropped(player: Player, owner_name: String): String = s"@CTF_FlagDropped^${player.Name}~^@${CaptureFlagChatMessageStrings.GetFactionString(player.Faction)}~^@$owner_name~"
|
||||
|
||||
// todo: make private
|
||||
private def GetFactionString(faction: PlanetSideEmpire.Value): String = {
|
||||
faction match {
|
||||
case PlanetSideEmpire.TR => "TerranRepublic"
|
||||
case PlanetSideEmpire.NC => "NewConglomerate"
|
||||
case PlanetSideEmpire.VS => "VanuSovereigncy" // Yes, this is wrong. It is like that in packet captures.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object CaptureFlagLostReasonEnum extends Enumeration {
|
||||
type CaptureFlagLostReasonEnum = Value
|
||||
|
||||
val Resecured, TimedOut = Value
|
||||
}
|
||||
|
|
@ -1,21 +1,26 @@
|
|||
package net.psforever.services.local.support
|
||||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.objects.{Default, GlobalDefinitions}
|
||||
import net.psforever.packet.game.PlanetsideAttributeEnum
|
||||
import net.psforever.packet.game.{GenericActionEnum, PlanetsideAttributeEnum}
|
||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
import scala.concurrent.duration.{FiniteDuration, _}
|
||||
import scala.util.Random
|
||||
|
||||
class HackCaptureActor extends Actor {
|
||||
/**
|
||||
* Responsible for handling the aspects related to hacking control consoles and capturing bases.
|
||||
*/
|
||||
class HackCaptureActor(val taskResolver: ActorRef) extends Actor {
|
||||
private[this] val log = org.log4s.getLogger
|
||||
|
||||
private var clearTrigger: Cancellable = Default.Cancellable
|
||||
|
|
@ -61,6 +66,7 @@ class HackCaptureActor extends Actor {
|
|||
RestartTimer()
|
||||
|
||||
NotifyHackStateChange(target, isResecured = false)
|
||||
TrySpawnCaptureFlag(target)
|
||||
|
||||
case HackCaptureActor.ProcessCompleteHacks() =>
|
||||
log.trace("Processing complete hacks")
|
||||
|
|
@ -75,7 +81,19 @@ class HackCaptureActor extends Actor {
|
|||
val hackedByFaction = entry.target.HackedBy.get.hackerFaction
|
||||
entry.target.Actor ! CommonMessages.ClearHack()
|
||||
|
||||
HackCompleted(entry.target, hackedByFaction)
|
||||
entry.target.Owner.asInstanceOf[Building].GetFlagSocket match {
|
||||
case Some(socket) =>
|
||||
// LLU was not delivered in time. Send resecured notifications
|
||||
entry.target.Owner.asInstanceOf[Building].GetFlag match {
|
||||
case Some(flag: CaptureFlag) => entry.target.Zone.LocalEvents ! CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.TimedOut)
|
||||
case None => log.warn(s"Failed to find capture flag matching socket ${socket.GUID}")
|
||||
}
|
||||
|
||||
NotifyHackStateChange(entry.target, isResecured = true)
|
||||
case None =>
|
||||
// Timed hack finished, capture the base
|
||||
HackCompleted(entry.target, hackedByFaction)
|
||||
}
|
||||
})
|
||||
|
||||
// If there's hacked objects left in the list restart the timer with the shortest hack time left
|
||||
|
|
@ -84,32 +102,79 @@ class HackCaptureActor extends Actor {
|
|||
case HackCaptureActor.ResecureCaptureTerminal(target, _) =>
|
||||
hackedObjects = hackedObjects.filterNot(x => x.target == target)
|
||||
|
||||
// If LLU exists it was not delivered. Send resecured notifications
|
||||
target.Owner.asInstanceOf[Building].GetFlag match {
|
||||
case Some(flag: CaptureFlag) => target.Zone.LocalEvents ! CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.Resecured)
|
||||
case None => ;
|
||||
}
|
||||
|
||||
NotifyHackStateChange(target, isResecured = true)
|
||||
|
||||
// Restart the timer in case the object we just removed was the next one scheduled
|
||||
RestartTimer()
|
||||
case HackCaptureActor.FlagCaptured(flag) =>
|
||||
log.warn(hackedObjects.toString())
|
||||
hackedObjects.find(_.target.GUID == flag.Owner.asInstanceOf[Building].CaptureTerminal.get.GUID) match {
|
||||
case Some(entry) =>
|
||||
val hackedByFaction = entry.target.HackedBy.get.hackerFaction
|
||||
hackedObjects = hackedObjects.filterNot(x => x == entry)
|
||||
HackCompleted(entry.target, hackedByFaction)
|
||||
|
||||
entry.target.Actor ! CommonMessages.ClearHack()
|
||||
|
||||
flag.Zone.LocalEvents ! CaptureFlagManager.Captured(flag)
|
||||
|
||||
// If there's hacked objects left in the list restart the timer with the shortest hack time left
|
||||
RestartTimer()
|
||||
case _ =>
|
||||
log.error(s"Attempted LLU capture for ${flag.Owner.asInstanceOf[Building].Name} but CC GUID ${flag.Owner.asInstanceOf[Building].CaptureTerminal.get.GUID} was not in list of hacked objects")
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
private def NotifyHackStateChange(target: CaptureTerminal, isResecured: Boolean): Unit = {
|
||||
val attribute_value = HackCaptureActor.GetHackUpdateAttributeValue(target, isResecured)
|
||||
private def TrySpawnCaptureFlag(terminal: CaptureTerminal): Unit = {
|
||||
// Handle LLUs if the base contains a LLU socket
|
||||
// If there are no neighbouring bases belonging to the hacking faction this will be handled as a regular timed hack (e.g. neutral base in enemy territory)
|
||||
val owner = terminal.Owner.asInstanceOf[Building]
|
||||
val hackingFaction = HackCaptureActor.GetHackingFaction(terminal).get
|
||||
val hackingFactionNeighbourBases = owner.Neighbours(hackingFaction)
|
||||
|
||||
hackingFactionNeighbourBases match {
|
||||
case Some(neighbours) =>
|
||||
if(owner.IsCtfBase) {
|
||||
// Find a random neighbouring base matching the hacking faction
|
||||
val targetBase = neighbours.toVector((new Random).nextInt(neighbours.size))
|
||||
|
||||
// Request LLU is created by CaptureFlagActor via LocalService
|
||||
terminal.Zone.LocalEvents ! CaptureFlagManager.SpawnCaptureFlag(terminal, targetBase, hackingFaction)
|
||||
}
|
||||
case None =>
|
||||
log.info("Couldn't find any neighbouring bases for LLU hack.")
|
||||
}
|
||||
}
|
||||
|
||||
private def NotifyHackStateChange(terminal: CaptureTerminal, isResecured: Boolean): Unit = {
|
||||
val attribute_value = HackCaptureActor.GetHackUpdateAttributeValue(terminal, isResecured)
|
||||
|
||||
// Notify all clients that CC has been hacked
|
||||
target.Zone.LocalEvents ! LocalServiceMessage(
|
||||
target.Zone.id,
|
||||
terminal.Zone.LocalEvents ! LocalServiceMessage(
|
||||
terminal.Zone.id,
|
||||
LocalAction.SendPlanetsideAttributeMessage(
|
||||
PlanetSideGUID(-1),
|
||||
target.GUID,
|
||||
terminal.GUID,
|
||||
PlanetsideAttributeEnum.ControlConsoleHackUpdate,
|
||||
attribute_value
|
||||
)
|
||||
)
|
||||
|
||||
val owner = terminal.Owner.asInstanceOf[Building]
|
||||
|
||||
// Notify parent building that state has changed
|
||||
target.Owner.Actor ! BuildingActor.AmenityStateChange(target, Some(isResecured))
|
||||
owner.Actor ! BuildingActor.AmenityStateChange(terminal, Some(isResecured))
|
||||
|
||||
// Push map update to clients
|
||||
target.Owner.asInstanceOf[Building].Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||
owner.Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||
}
|
||||
|
||||
private def HackCompleted(terminal: CaptureTerminal with Hackable, hackedByFaction: PlanetSideEmpire.Value): Unit = {
|
||||
|
|
@ -117,6 +182,9 @@ class HackCaptureActor extends Actor {
|
|||
if (building.NtuLevel > 0) {
|
||||
log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction")
|
||||
building.Actor! BuildingActor.SetFaction(hackedByFaction)
|
||||
|
||||
// todo: This should probably only go to those within the captured SOI who belong to the capturing faction
|
||||
building.Zone.LocalEvents ! LocalServiceMessage(building.Zone.id, LocalAction.SendGenericActionMessage(PlanetSideGUID(-1), GenericActionEnum.BaseCaptureFanfare))
|
||||
} else {
|
||||
log.info("Base hack completed, but base was out of NTU.")
|
||||
}
|
||||
|
|
@ -160,6 +228,7 @@ object HackCaptureActor {
|
|||
)
|
||||
|
||||
final case class ResecureCaptureTerminal(target: CaptureTerminal, zone: Zone)
|
||||
final case class FlagCaptured(flag: CaptureFlag)
|
||||
|
||||
private final case class ProcessCompleteHacks()
|
||||
|
||||
|
|
@ -172,11 +241,19 @@ object HackCaptureActor {
|
|||
hack_timestamp: Long
|
||||
)
|
||||
|
||||
def GetHackUpdateAttributeValue(target: CaptureTerminal, isResecured: Boolean): Long = {
|
||||
def GetHackingFaction(terminal: CaptureTerminal): Option[PlanetSideEmpire.Value] = {
|
||||
terminal.HackedBy match {
|
||||
case Some(Hackable.HackInfo(_, _, hackingFaction, _, _, _)) =>
|
||||
Some(hackingFaction)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
def GetHackUpdateAttributeValue(terminal: CaptureTerminal, isResecured: Boolean): Long = {
|
||||
if (isResecured) {
|
||||
17039360L
|
||||
} else {
|
||||
target.HackedBy match {
|
||||
terminal.HackedBy match {
|
||||
case Some(Hackable.HackInfo(_, _, hackingFaction, _, start, length)) =>
|
||||
// See PlanetSideAttributeMessage #20 documentation for an explanation of how the timer is calculated
|
||||
val hack_time_remaining_ms =
|
||||
|
|
|
|||
|
|
@ -248,14 +248,24 @@ object ChatMessageType extends Enum[ChatMessageType] {
|
|||
case object CMT_REMOVE_VANUMODULE extends ChatMessageType // /moduleremove OR /modulerm
|
||||
case object CMT_DEBUG_MASSIVE extends ChatMessageType // /debugmassive
|
||||
case object CMT_WARP_TO_NEXT_BILLBOARD extends ChatMessageType // ???
|
||||
case object UNK_222 extends ChatMessageType // ??? "CTF Flag stolen"
|
||||
case object UNK_223 extends ChatMessageType // ??? "CTF Flag lost"
|
||||
case object UNK_222 extends ChatMessageType // "CTF Flag stolen"
|
||||
// Plays a trumpet-like sound and displays the message: "<Base Type> <Base Name> has spawned a LLU"
|
||||
// "It must be taken to <Base Type> <Base Name>'s Control Console within 15 minutes or the hack will fail!"
|
||||
// Example string: @CTF_FlagSpawned^@cryo_facility~^@Hanish~^@comm_station_dsp~^@Akkan~^15~
|
||||
case object UNK_223 extends ChatMessageType // "CTF Flag lost"
|
||||
// Handles both LLU lost and LLU resecured
|
||||
// Example string: @CTF_Failed_SourceResecured^@TerranRepublic~^@Hanish~
|
||||
// Output: "The Terran Republic resecured Hanish!" "The LLU was lost!"
|
||||
// Example string: @CTF_Failed_FlagLost^@TerranRepublic~^@Hanish~
|
||||
// Output: "The Terran Republic lost Hanish's LLU" "Hack canceled!"
|
||||
case object UNK_224 extends ChatMessageType // ??? "Vehicle Dismount"
|
||||
case object UNK_225 extends ChatMessageType // ??? empty
|
||||
case object UNK_226 extends ChatMessageType // ??? empty
|
||||
case object UNK_227 extends ChatMessageType // ??? empty
|
||||
case object UNK_228 extends ChatMessageType // ??? empty
|
||||
case object UNK_229 extends ChatMessageType // ??? empty
|
||||
case object UNK_229 extends ChatMessageType // See UNK_222 - seems to do the same except without trumpet-like sound
|
||||
// Is used for flag pickup @CTF_FlagPickedUp^OzTurtle~^@NewConglomerate~^@Qumu~
|
||||
// Or flag warning @CTF_Warning_Carrier^VanuHemlock~^@VanuSovereigncy~^@Mani~^@Dagur~^10~
|
||||
case object UNK_230 extends ChatMessageType // ??? "Vehicle Mount"
|
||||
case object UNK_231 extends ChatMessageType // ??? empty
|
||||
case object UNK_232 extends ChatMessageType // ??? empty
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import net.psforever.objects.ballistics.Projectile
|
|||
import net.psforever.objects.definition.BasicDefinition
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.serverobject.generator.Generator
|
||||
import net.psforever.objects.serverobject.llu.{CaptureFlagSocket, CaptureFlagSocketDefinition}
|
||||
import net.psforever.objects.serverobject.locks.IFFLock
|
||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnPad, VehicleSpawnPadDefinition}
|
||||
import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition}
|
||||
|
|
@ -338,6 +339,15 @@ object Zones {
|
|||
),
|
||||
owningBuildingGuid = ownerGuid
|
||||
)
|
||||
case "llm_socket" =>
|
||||
zoneMap.addLocalObject(
|
||||
obj.guid,
|
||||
CaptureFlagSocket.Constructor(
|
||||
obj.objectDefinition.asInstanceOf[CaptureFlagSocketDefinition],
|
||||
obj.position
|
||||
),
|
||||
owningBuildingGuid = ownerGuid
|
||||
)
|
||||
|
||||
case "gr_door_mb_orb" =>
|
||||
zoneMap
|
||||
|
|
|
|||
48
src/test/scala/game/CaptureFlagUpdateMessageTest.scala
Normal file
48
src/test/scala/game/CaptureFlagUpdateMessageTest.scala
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package game
|
||||
|
||||
import net.psforever.packet.PacketCoding
|
||||
import net.psforever.packet.game.{CaptureFlagUpdateMessage, FlagInfo}
|
||||
import org.specs2.control.Debug
|
||||
import org.specs2.mutable.Specification
|
||||
import scodec.bits._
|
||||
|
||||
class CaptureFlagUpdateMessageTest extends Specification with Debug {
|
||||
val stringZero = hex"c0 0a0000"
|
||||
val stringOne = hex"c0 0a0014300018025281dd852830803000"
|
||||
|
||||
"decode (zero)" in {
|
||||
PacketCoding.decodePacket(stringZero).require match {
|
||||
case CaptureFlagUpdateMessage(zone_number, flagInfoList) =>
|
||||
zone_number mustEqual 10
|
||||
flagInfoList.length mustEqual 0
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"decode (one)" in {
|
||||
PacketCoding.decodePacket(stringOne).require match {
|
||||
case CaptureFlagUpdateMessage(zone_number, flagInfoList) =>
|
||||
zone_number mustEqual 10
|
||||
flagInfoList.length mustEqual 1
|
||||
flagInfoList.head mustEqual FlagInfo(1, 12, 6, 3905.1562f, 5160.922f, 794636L, false)
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"encode (zero)" in {
|
||||
val msg = CaptureFlagUpdateMessage(10, Nil)
|
||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual stringZero
|
||||
}
|
||||
|
||||
"encode (one)" in {
|
||||
val msg = CaptureFlagUpdateMessage(10, List(FlagInfo(1, 12, 6, 3905.1562f, 5160.922f, 794636L, false)))
|
||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual stringOne
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -29,24 +29,16 @@ class CaptureFlagDataTest extends Specification {
|
|||
flag.pos.orient.y mustEqual 0f
|
||||
flag.pos.orient.z mustEqual 47.8125f
|
||||
flag.faction mustEqual PlanetSideEmpire.NC
|
||||
flag.unk1 mustEqual 21
|
||||
flag.unk2 mustEqual 4
|
||||
flag.unk3 mustEqual 2838
|
||||
flag.unk4 mustEqual 9
|
||||
flag.owningBaseGuid mustEqual 21
|
||||
flag.targetBaseGuid mustEqual 4
|
||||
flag.milliseconds_remaining mustEqual 592662
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"encode" in {
|
||||
val obj = CaptureFlagData(
|
||||
PlacementData(3912.0312f, 5169.4375f, 59.96875f, 0f, 0f, 47.8125f),
|
||||
PlanetSideEmpire.NC,
|
||||
21,
|
||||
4,
|
||||
2838,
|
||||
9
|
||||
)
|
||||
val obj = CaptureFlagData(PlacementData(3912.0312f, 5169.4375f, 59.96875f, 0f, 0f, 47.8125f), PlanetSideEmpire.NC, 21, 4, 592662)
|
||||
val msg = ObjectCreateMessage(ObjectClass.capture_flag, PlanetSideGUID(4330), obj)
|
||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||
pkt mustEqual string_captureflag
|
||||
|
|
|
|||
|
|
@ -526,7 +526,7 @@ class PlayerControlDeathStandingTest extends ActorTest {
|
|||
assert(player2.isAlive)
|
||||
|
||||
player2.Actor ! Vitality.Damage(applyDamageTo)
|
||||
val msg_avatar = avatarProbe.receiveN(7, 500 milliseconds)
|
||||
val msg_avatar = avatarProbe.receiveN(8, 500 milliseconds)
|
||||
val msg_stamina = probe.receiveOne(500 milliseconds)
|
||||
activityProbe.expectNoMessage(200 milliseconds)
|
||||
assert(
|
||||
|
|
@ -543,25 +543,31 @@ class PlayerControlDeathStandingTest extends ActorTest {
|
|||
)
|
||||
assert(
|
||||
msg_avatar(1) match {
|
||||
case AvatarServiceMessage("TestCharacter2", AvatarAction.DropSpecialItem()) => true
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(2) match {
|
||||
case AvatarServiceMessage("TestCharacter2", AvatarAction.Killed(PlanetSideGUID(2), None)) => true
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(2) match {
|
||||
msg_avatar(3) match {
|
||||
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(3) match {
|
||||
msg_avatar(4) match {
|
||||
case AvatarServiceMessage("TestCharacter2", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 7, _)) =>
|
||||
true
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(4) match {
|
||||
msg_avatar(5) match {
|
||||
case AvatarServiceMessage(
|
||||
"TestCharacter2",
|
||||
AvatarAction.SendResponse(_, DestroyMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _))
|
||||
|
|
@ -571,7 +577,7 @@ class PlayerControlDeathStandingTest extends ActorTest {
|
|||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(5) match {
|
||||
msg_avatar(6) match {
|
||||
case AvatarServiceMessage(
|
||||
"TestCharacter2",
|
||||
AvatarAction.SendResponse(
|
||||
|
|
@ -584,7 +590,7 @@ class PlayerControlDeathStandingTest extends ActorTest {
|
|||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(6) match {
|
||||
msg_avatar(7) match {
|
||||
case AvatarServiceMessage("test", AvatarAction.DestroyDisplay(killer, victim, _, _))
|
||||
if killer.Name.equals(player1.Name) && victim.Name.equals(player2.Name) =>
|
||||
true
|
||||
|
|
@ -666,7 +672,7 @@ class PlayerControlDeathSeatedTest extends ActorTest {
|
|||
assert(player2.isAlive)
|
||||
|
||||
player2.Actor ! Vitality.Damage(applyDamageTo)
|
||||
val msg_avatar = avatarProbe.receiveN(8, 500 milliseconds)
|
||||
val msg_avatar = avatarProbe.receiveN(9, 500 milliseconds)
|
||||
val msg_stamina = probe.receiveOne(500 milliseconds)
|
||||
activityProbe.expectNoMessage(200 milliseconds)
|
||||
assert(
|
||||
|
|
@ -677,6 +683,12 @@ class PlayerControlDeathSeatedTest extends ActorTest {
|
|||
)
|
||||
assert(
|
||||
msg_avatar.head match {
|
||||
case AvatarServiceMessage("TestCharacter2", AvatarAction.DropSpecialItem()) => true
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(1) match {
|
||||
case AvatarServiceMessage(
|
||||
"TestCharacter2",
|
||||
AvatarAction.Killed(PlanetSideGUID(2), Some(PlanetSideGUID(7)))
|
||||
|
|
@ -686,7 +698,7 @@ class PlayerControlDeathSeatedTest extends ActorTest {
|
|||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(1) match {
|
||||
msg_avatar(2) match {
|
||||
case AvatarServiceMessage(
|
||||
"TestCharacter2",
|
||||
AvatarAction.SendResponse(_, ObjectDetachMessage(PlanetSideGUID(7), PlanetSideGUID(2), _, _, _, _))
|
||||
|
|
@ -696,7 +708,7 @@ class PlayerControlDeathSeatedTest extends ActorTest {
|
|||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(2) match {
|
||||
msg_avatar(3) match {
|
||||
case AvatarServiceMessage(
|
||||
"TestCharacter2",
|
||||
AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 29, 1)
|
||||
|
|
@ -706,19 +718,19 @@ class PlayerControlDeathSeatedTest extends ActorTest {
|
|||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(3) match {
|
||||
msg_avatar(4) match {
|
||||
case AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(2), PlanetSideGUID(2), _)) => true
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(4) match {
|
||||
msg_avatar(5) match {
|
||||
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(5) match {
|
||||
msg_avatar(6) match {
|
||||
case AvatarServiceMessage(
|
||||
"TestCharacter2",
|
||||
AvatarAction.SendResponse(_, DestroyMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _))
|
||||
|
|
@ -728,7 +740,7 @@ class PlayerControlDeathSeatedTest extends ActorTest {
|
|||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(6) match {
|
||||
msg_avatar(7) match {
|
||||
case AvatarServiceMessage(
|
||||
"TestCharacter2",
|
||||
AvatarAction.SendResponse(
|
||||
|
|
@ -741,7 +753,7 @@ class PlayerControlDeathSeatedTest extends ActorTest {
|
|||
}
|
||||
)
|
||||
assert(
|
||||
msg_avatar(7) match {
|
||||
msg_avatar(8) match {
|
||||
case AvatarServiceMessage("test", AvatarAction.DestroyDisplay(killer, victim, _, _))
|
||||
if killer.Name.equals(player1.Name) && victim.Name.equals(player2.Name) =>
|
||||
true
|
||||
|
|
|
|||
Loading…
Reference in a new issue