mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-28 21:01:30 +00:00
ENH - detect payphones and spawn custom locations
Remove the static vanilla payphone coordinate list so configured prop models are detected directly in the streamed world. Add vector4-based custom locations that spawn the selected custom prop, and validate detected booth models and player proximity server-side.
This commit is contained in:
@@ -103,7 +103,7 @@ The files contain clearly separated sections for:
|
||||
| `Config.Phone` | Phone item, movement, unique-device mode, and development command |
|
||||
| `Config.Sim` | Physical or virtual SIM behavior and number formatting |
|
||||
| `Config.Calls` / `Config.Radio` | Voice providers, call behavior, radio limits, and permissions |
|
||||
| `Config.Payphones` | Payphone pricing, props, validation, and server-owned locations |
|
||||
| `Config.Payphones` | Payphone pricing, detected props, validation, and custom spawned locations |
|
||||
| `Config.Animations` | Phone prop, animations, and portrait/landscape transforms |
|
||||
| App sections | Limits and behavior for every built-in app |
|
||||
| `Config.Server` | Stable password and passcode peppers |
|
||||
@@ -353,17 +353,18 @@ Radio display-name permissions are configured in `Config.Radio.DisplayName.Allow
|
||||
|
||||
## Payphones
|
||||
|
||||
Sky Phone includes server-authoritative GTA V payphone locations. Pricing, payment account, props, validation distances, and custom locations are configured under `Config.Payphones`.
|
||||
Sky Phone automatically detects nearby world props listed in `Config.Payphones.Props`; GTA V payphones do not need configured coordinates. Pricing, payment account, prop models, and validation distances are configured under `Config.Payphones`.
|
||||
|
||||
Custom location example:
|
||||
Use `CustomLocations` only when Sky Phone should spawn additional payphone props at custom positions:
|
||||
|
||||
```lua
|
||||
Config.Payphones.Locations = {
|
||||
{ model = "prop_phonebox_01a", coords = { x = 123.45, y = 678.90, z = 21.0 } },
|
||||
Config.Payphones.CustomProp = "prop_phonebox_01b"
|
||||
Config.Payphones.CustomLocations = {
|
||||
vector4(123.45, 678.90, 21.0, 90.0),
|
||||
}
|
||||
```
|
||||
|
||||
The model must also be listed in `Config.Payphones.Props`.
|
||||
`CustomProp` must also be listed in `Config.Payphones.Props`. Each custom position uses `vector4(x, y, z, heading)`.
|
||||
|
||||
## Commands
|
||||
|
||||
|
||||
+6
-253
@@ -90,12 +90,18 @@ Config.Calls = {
|
||||
|
||||
Config.Payphones = {
|
||||
Enabled = true,
|
||||
-- Existing world props with these models are detected automatically.
|
||||
Props = {
|
||||
"prop_phonebox_01b",
|
||||
"p_phonebox_01b_s",
|
||||
"prop_phonebox_01a",
|
||||
"prop_phonebox_04",
|
||||
},
|
||||
-- Additional booths are spawned only at these custom positions.
|
||||
CustomProp = "prop_phonebox_01b",
|
||||
CustomLocations = {
|
||||
-- vector4(x, y, z, heading),
|
||||
},
|
||||
ReplacementProp = "sf_prop_sf_phonebox_01b_s",
|
||||
PricePerSecond = 1,
|
||||
PaymentAccount = "cash", -- cash or bank
|
||||
@@ -659,259 +665,6 @@ if IsDuplicityVersion() then
|
||||
PicstagramPasswordPepper = "653e41dd19aba5ef750a668ad1886273ba7d0e0420bd5c745748df80a6e22676",
|
||||
}
|
||||
|
||||
-- -------------------------------------------------------------------------
|
||||
-- Server-owned payphone locations
|
||||
-- -------------------------------------------------------------------------
|
||||
|
||||
-- Server-owned vanilla payphone positions used for authoritative proximity checks.
|
||||
-- Generated from DurtyFree/gta-v-data-dumps worldPublicPhones.json at commit b65684e00f689fdec405c5f1055322c802d3c895.
|
||||
-- Add custom-map booths here; their model must also be listed in Config.Payphones.Props.
|
||||
Config.Payphones.Locations = {
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1819.2284, y = 796.32294, z = 137.12784 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1773.0256, y = -503.15234, z = 37.80706 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1772.2114, y = -504.00488, z = 37.81461 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1457.3734, y = -148.68604, z = 48.7486 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1456.838, y = -149.31949, z = 48.68604 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1456.3501, y = -149.95428, z = 48.61642 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1438.6545, y = -210.77448, z = 47.10766 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1418.2983, y = -291.36002, z = 42.96778 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1417.4769, y = -290.64453, z = 42.93899 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1416.5211, y = -289.8119, z = 42.90134 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1318.0975, y = -380.79547, z = 35.73553 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1316.9534, y = -378.42676, z = 35.74885 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1316.2688, y = -378.07245, z = 35.73169 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1315.5924, y = -377.7347, z = 35.72274 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1261.6484, y = -519.13086, z = 30.83657 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1260.9482, y = -519.9344, z = 30.75686 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1260.0995, y = -520.9083, z = 30.66707 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1121.5917, y = -825.6313, z = 14.94339 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1120.9409, y = -825.0698, z = 14.98657 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1120.2446, y = -824.4812, z = 15.06407 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1079.6154, y = -451.0622, z = 35.6144 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1079.23, y = -451.8739, z = 35.62138 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -1078.874, y = -452.55182, z = 35.62138 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -956.56256, y = -403.17123, z = 36.81676 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -956.1004, y = -404.09232, z = 36.81755 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -524.4403, y = -300.71704, z = 34.26753 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -523.64453, y = -300.41074, z = 34.26273 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -522.872, y = -300.1134, z = 34.25807 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -449.44238, y = -272.8244, z = 34.93996 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -448.8816, y = -274.12805, z = 34.96191 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -448.36926, y = -275.31906, z = 34.96507 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -329.23917, y = 6224.885, z = 30.47861 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -310.30554, y = 6205.3, z = 30.4465 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -280.64215, y = 6224.2314, z = 30.45544 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -243.25082, y = 279.90717, z = 91.04989 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -234.61494, y = 6176.931, z = 30.43884 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -233.6865, y = 6176.0547, z = 30.43884 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -184.35658, y = 6331.4697, z = 30.48767 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -183.68753, y = 6332.1597, z = 30.48987 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -154.76048, y = 6352.27, z = 30.56079 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -153.88358, y = 6351.417, z = 30.56079 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -119.91727, y = 6287.283, z = 30.45911 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -119.44898, y = 6286.768, z = 30.45911 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -92.08037, y = 6462.644, z = 30.44397 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -90.61212, y = 6464.0566, z = 30.44397 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -46.3855, y = 6511.0156, z = 30.44861 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -25.6331, y = 6495.123, z = 30.48767 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = -24.59157, y = 6496.0537, z = 30.48767 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 110.07694, y = -1694.206, z = 28.29156 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 136.9704, y = 196.05042, z = 105.73364 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 137.75732, y = 195.764, z = 105.70988 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 138.48807, y = 195.49808, z = 105.69342 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 173.45892, y = -1547.1165, z = 28.25158 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 215.71725, y = -1783.2102, z = 27.99637 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 215.94612, y = -1518.9603, z = 28.29362 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 228.6216, y = -1545.9579, z = 28.28108 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 229.1375, y = -1545.6771, z = 28.28108 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 295.67847, y = -1360.8624, z = 30.91401 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 296.17984, y = -1360.2825, z = 30.91899 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 532.401, y = -151.79816, z = 56.07613 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 539.5577, y = -166.04846, z = 53.4862 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 812.21716, y = -289.03873, z = 65.46264 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 812.3678, y = -289.84793, z = 65.46264 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 819.023, y = -94.03439, z = 79.57648 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 819.37396, y = -93.47577, z = 79.57648 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 891.8809, y = -140.80609, z = 76.11372 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 963.6167, y = -142.79822, z = 73.46588 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1079.2015, y = -776.68054, z = 57.25418 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1156.3375, y = -776.99866, z = 56.58559 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1159.7463, y = -374.87518, z = 66.51784 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1166.4825, y = -321.59958, z = 68.25383 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1169.4127, y = 2702.8025, z = 36.99265 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1170.3059, y = -455.76053, z = 65.49249 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1172.7772, y = -297.61606, z = 68.01613 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1172.8646, y = -298.23972, z = 68.01981 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1173.8961, y = -421.43643, z = 66.07632 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1201.426, y = -488.8848, z = 64.67129 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1222.6125, y = -397.32706, z = 67.32355 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 1801.4076, y = 4597.0137, z = 36.67796 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 2558.9167, y = 367.14368, z = 107.63403 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1684.4233, y = -266.45306, z = 50.89204 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1683.9019, y = -265.70874, z = 50.89204 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1543.9277, y = -433.13232, z = 34.57933 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1543.0599, y = -432.05966, z = 34.58469 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1522.4791, y = -407.05118, z = 34.58695 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1412.1201, y = -383.80542, z = 35.68469 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1205.1965, y = -1393.6274, z = 3.07721 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1150.6671, y = -1392.6455, z = 4.11812 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1142.0598, y = -725.3442, z = 19.77577 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1080.87, y = -2574.942, z = 12.91528 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1061.7015, y = -2541.7412, z = 12.91528 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1061.5474, y = -2541.4744, z = 19.15571 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1046.9408, y = -2516.175, z = 12.91528 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1046.8787, y = -2516.0674, z = 19.15571 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1034.5115, y = -2494.6467, z = 19.15571 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -1024.4517, y = -2477.2227, z = 12.91528 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -765.40045, y = -848.8706, z = 21.11398 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -764.83673, y = -848.8654, z = 21.13071 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -756.90735, y = 5586.8223, z = 35.71351 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -756.90735, y = 5587.636, z = 35.71351 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -745.72156, y = 5558.714, z = 35.71351 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -743.95874, y = 5558.714, z = 35.71351 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -715.921, y = 123.33502, z = 54.99648 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -715.40906, y = 123.65546, z = 55.01274 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -700.7271, y = -916.8699, z = 18.21408 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -700.1226, y = -916.8699, z = 18.21408 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -685.93774, y = -854.8967, z = 22.88396 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -670.3093, y = -819.59973, z = 23.4098 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -669.60815, y = -819.6056, z = 23.42427 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -668.81213, y = -819.6378, z = 23.43811 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -665.19354, y = -670.83777, z = 30.40002 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -664.59607, y = -670.8341, z = 30.40393 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -663.99866, y = -670.83044, z = 30.41797 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -655.2001, y = -859.74493, z = 23.50043 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -654.1605, y = -707.27155, z = 28.40153 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -654.1605, y = -706.51654, z = 28.47383 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -654.1605, y = -705.7615, z = 28.54753 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -611.56744, y = -2237.6104, z = 5.10603 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -530.0182, y = -1286.1543, z = 25.03622 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -529.77765, y = -1285.6444, z = 25.04207 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -529.6009, y = -1286.3458, z = 25.04428 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -529.36365, y = -1285.8345, z = 25.03622 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -468.24023, y = -396.44247, z = 32.8951 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -467.58286, y = -396.50574, z = 32.8951 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -259.3869, y = -604.76556, z = 32.59827 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -259.14352, y = -603.98016, z = 32.65002 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -241.57574, y = -766.2026, z = 31.73654 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -241.29694, y = -765.4682, z = 31.77955 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -239.74597, y = -978.22943, z = 28.26393 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -239.51797, y = -977.59296, z = 28.26393 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -178.84961, y = -52.06338, z = 51.10093 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -177.28662, y = -713.48505, z = 33.39728 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -147.61765, y = -287.15277, z = 39.43044 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -147.37784, y = -286.44186, z = 39.49831 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -73.17541, y = -641.5052, z = 35.24065 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -72.92773, y = -640.8415, z = 35.24065 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -53.45404, y = -94.169, z = 56.7686 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -27.98413, y = -100.90671, z = 56.35694 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -26.48154, y = -110.65947, z = 56.06785 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -8.06136, y = -731.61005, z = 43.22259 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = -7.37235, y = -731.8549, z = 43.22768 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 43.99314, y = -680.87616, z = 43.20672 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 44.30204, y = -680.0512, z = 43.20672 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 120.37446, y = -205.12677, z = 53.61985 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 121.18489, y = -205.42413, z = 53.61985 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 129.40686, y = 245.3497, z = 106.42847 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 140.18076, y = -1033.1602, z = 28.34242 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 174.5452, y = -1116.4456, z = 28.28443 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 175.22937, y = -1116.4185, z = 28.28425 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 213.8157, y = -852.6208, z = 29.38956 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 214.44952, y = -852.86725, z = 29.38709 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 233.49872, y = 334.44766, z = 104.52145 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 296.66183, y = -1359.7725, z = 30.92093 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 372.30563, y = -966.37286, z = 28.41298 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 394.25433, y = -799.7535, z = 28.23798 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 394.25433, y = -798.6486, z = 28.23798 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 397.567, y = -921.3287, z = 28.3982 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 397.567, y = -920.658, z = 28.3982 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 415.17245, y = -910.94476, z = 28.3982 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 436.0411, y = 137.20285, z = 99.43968 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 436.83813, y = 136.89954, z = 99.38892 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 439.8047, y = -606.65063, z = 27.69825 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 439.99564, y = -604.67474, z = 27.69747 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 445.3808, y = 3567.5305, z = 32.21765 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 452.6532, y = -612.11816, z = 27.54012 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 452.7997, y = -610.4434, z = 27.5457 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 535.5781, y = 102.93228, z = 95.56698 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 779.83923, y = -1755.3914, z = 28.47611 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 780.2285, y = -1755.4475, z = 28.46564 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 809.3085, y = -1074.9281, z = 27.67919 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 903.52423, y = 3646.1294, z = 31.70571 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1051.0497, y = 2661.3877, z = 38.52392 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1181.1997, y = 2703.214, z = 37.1464 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1206.4275, y = 2647.8894, z = 36.81204 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1401.1744, y = 3602.0786, z = 34.01619 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1662.8026, y = 4841.53, z = 41.0313 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1662.9365, y = 4840.332, z = 41.0313 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1692.9031, y = 6432.025, z = 31.73361 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1696.5485, y = 3776.0618, z = 33.71252 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1696.7177, y = 4790.302, z = 40.89749 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1860.4072, y = 3696.2563, z = 33.26152 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 1861.0801, y = 3695.0903, z = 33.26152 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 2005.9707, y = 3782.6196, z = 31.15662 } },
|
||||
{ model = "prop_phonebox_01b", coords = { x = 2006.7942, y = 3783.1003, z = 31.14984 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -2969.4265, y = 397.46487, z = 14.10208 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1417.7056, y = -94.50974, z = 51.41046 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1416.8014, y = -94.11159, z = 51.44441 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1415.9122, y = -93.72023, z = 51.49042 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1294.0234, y = -390.34976, z = 35.44277 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1293.4121, y = -391.38864, z = 35.44632 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1241.7491, y = -464.37216, z = 32.537 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1224.2532, y = -322.51794, z = 36.57259 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1223.0624, y = -321.95178, z = 36.59326 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1074.0209, y = -397.75607, z = 35.95449 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1025.3336, y = -216.04681, z = 36.93829 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -1023.97375, y = -216.74884, z = 36.9369 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -985.19824, y = -414.10977, z = 36.85289 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -979.73254, y = -369.2069, z = 36.856 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -979.1488, y = -370.3092, z = 36.856 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -965.37616, y = -2524.3992, z = 13.00643 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -963.65985, y = -247.05435, z = 37.0568 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -896.8487, y = -247.80585, z = 39.07844 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -865.3409, y = -2528.5645, z = 13.00643 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -821.83124, y = -251.49579, z = 36.0627 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -821.29346, y = -252.4495, z = 36.05127 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -701.46173, y = -371.56976, z = 33.2833 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -700.3627, y = -372.04968, z = 33.27078 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -619.5328, y = -207.68121, z = 36.3736 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -618.975, y = -208.61508, z = 36.35005 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -617.05457, y = -422.20978, z = 33.7873 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -557.25586, y = -386.67517, z = 34.11347 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -556.05286, y = -386.66565, z = 34.11989 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -554.8701, y = -386.6563, z = 34.12583 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -546.57184, y = -334.10083, z = 34.16116 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -544.17737, y = -157.39006, z = 37.53791 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -388.49542, y = -321.52948, z = 32.10458 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -387.68488, y = -322.21454, z = 32.05279 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -360.33978, y = -267.18268, z = 32.73604 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -347.059, y = -1490.9738, z = 29.79159 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -345.83786, y = -1490.9738, z = 29.7867 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -263.0376, y = -766.90546, z = 31.57576 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -262.6508, y = -766.04095, z = 31.60592 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -213.1738, y = -696.5944, z = 32.80729 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -174.76907, y = -674.9272, z = 33.27862 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -173.80676, y = -675.35236, z = 33.29762 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -138.00961, y = -799.9025, z = 31.10711 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = -137.64026, y = -798.8024, z = 31.14563 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 55.44337, y = -1081.1333, z = 28.45174 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 55.90165, y = -1080.282, z = 28.45174 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 188.01767, y = -1043.9451, z = 28.32789 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 189.79306, y = -1044.5588, z = 28.32789 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 298.28317, y = -795.153, z = 28.4778 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 298.62607, y = -794.289, z = 28.4778 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 347.45938, y = -730.9255, z = 28.28353 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 564.7501, y = -1748.7141, z = 28.31245 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 653.1738, y = 272.5705, z = 102.29323 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 654.2313, y = 271.95996, z = 102.29323 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 1214.8445, y = -1385.6348, z = 34.34755 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 1214.8445, y = -1384.5386, z = 34.34755 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 1662.002, y = 4819.523, z = 41.04535 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 1816.4236, y = 3671.6497, z = 33.29268 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 1818.1936, y = 3668.7485, z = 33.29268 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 2007.0574, y = 3784.7974, z = 31.20895 } },
|
||||
}
|
||||
|
||||
-- -------------------------------------------------------------------------
|
||||
-- Company directory
|
||||
-- -------------------------------------------------------------------------
|
||||
|
||||
@@ -18,6 +18,7 @@ local visuals_starting = false
|
||||
local visuals_ending = false
|
||||
local hangup_requested = false
|
||||
local remote_visuals = {}
|
||||
local custom_payphone_props = {}
|
||||
|
||||
local configured_models = {}
|
||||
for _, model_name in ipairs(Config.Payphones.Props or {}) do
|
||||
@@ -97,6 +98,64 @@ local function load_model(model_hash)
|
||||
return HasModelLoaded(model_hash)
|
||||
end
|
||||
|
||||
local function spawn_custom_payphones()
|
||||
local locations = Config.Payphones.CustomLocations or {}
|
||||
if not Config.Payphones.Enabled or #locations == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local model_name = Config.Payphones.CustomProp
|
||||
local model_hash = type(model_name) == "string" and joaat(model_name) or 0
|
||||
if not configured_models[model_hash] then
|
||||
Bridge.Debug(
|
||||
"error",
|
||||
"[sky_phone] Config.Payphones.CustomProp must also be listed in Config.Payphones.Props.",
|
||||
{ always = true }
|
||||
)
|
||||
return
|
||||
end
|
||||
if not load_model(model_hash) then
|
||||
Bridge.Debug("error", "[sky_phone] The configured custom payphone prop could not be loaded.", {
|
||||
always = true,
|
||||
})
|
||||
return
|
||||
end
|
||||
|
||||
for index, coords in ipairs(locations) do
|
||||
local coords_type = type(coords)
|
||||
local x = (coords_type == "vector4" or coords_type == "table")
|
||||
and valid_visual_number(coords.x, 10000.0) or nil
|
||||
local y = x and valid_visual_number(coords.y, 10000.0) or nil
|
||||
local z = y and valid_visual_number(coords.z, 2000.0) or nil
|
||||
local heading = z and valid_visual_number(coords.w, 360000.0) or nil
|
||||
if not heading then
|
||||
Bridge.Debug(
|
||||
"error",
|
||||
"[sky_phone] Ignored invalid Config.Payphones.CustomLocations entry %s; use vector4(x, y, z, heading).",
|
||||
index,
|
||||
{ always = true }
|
||||
)
|
||||
else
|
||||
local entity = CreateObjectNoOffset(model_hash, x, y, z, false, true, false)
|
||||
if entity == 0 or not DoesEntityExist(entity) then
|
||||
Bridge.Debug(
|
||||
"error",
|
||||
"[sky_phone] Failed to spawn custom payphone %s.",
|
||||
index,
|
||||
{ always = true }
|
||||
)
|
||||
else
|
||||
SetEntityHeading(entity, heading % 360.0)
|
||||
FreezeEntityPosition(entity, true)
|
||||
custom_payphone_props[#custom_payphone_props + 1] = entity
|
||||
end
|
||||
end
|
||||
end
|
||||
SetModelAsNoLongerNeeded(model_hash)
|
||||
end
|
||||
|
||||
CreateThread(spawn_custom_payphones)
|
||||
|
||||
local function load_animation(dictionary)
|
||||
if HasAnimDictLoaded(dictionary) then
|
||||
return true
|
||||
@@ -667,4 +726,10 @@ AddEventHandler("onResourceStop", function(resource_name)
|
||||
for _, id in ipairs(visual_ids) do
|
||||
restore_remote_visual(id)
|
||||
end
|
||||
for _, entity in ipairs(custom_payphone_props) do
|
||||
if DoesEntityExist(entity) then
|
||||
SetEntityAsMissionEntity(entity, true, true)
|
||||
DeleteEntity(entity)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -1074,34 +1074,23 @@ for _, model_name in ipairs(Config.Payphones.Props or {}) do
|
||||
end
|
||||
end
|
||||
|
||||
local payphone_locations, rejected_payphone_locations = SkyPhonePayphones.ValidateLocations(
|
||||
Config.Payphones.Locations,
|
||||
payphone_models
|
||||
)
|
||||
if Config.Payphones.Enabled and #payphone_locations == 0 then
|
||||
if Config.Payphones.Enabled and not next(payphone_models) then
|
||||
Bridge.Debug(
|
||||
"error",
|
||||
"[sky_phone] Payphones are enabled, but no valid server-owned locations are configured; payphone calls will be rejected.",
|
||||
{ always = true }
|
||||
)
|
||||
elseif Config.Payphones.Enabled and rejected_payphone_locations > 0 then
|
||||
Bridge.Debug(
|
||||
"warn",
|
||||
"[sky_phone] Ignored %s invalid server-owned payphone location(s).",
|
||||
rejected_payphone_locations,
|
||||
"[sky_phone] Payphones are enabled, but Config.Payphones.Props contains no valid models; payphone calls will be rejected.",
|
||||
{ always = true }
|
||||
)
|
||||
end
|
||||
|
||||
local function valid_payphone_position(source)
|
||||
local function valid_payphone_position(source, detected_booth)
|
||||
local ped = GetPlayerPed(source)
|
||||
if not ped or ped == 0 then
|
||||
return nil
|
||||
end
|
||||
local player_coords = GetEntityCoords(ped)
|
||||
local location = SkyPhonePayphones.FindNearest(
|
||||
payphone_locations,
|
||||
player_coords,
|
||||
local location = SkyPhonePayphones.ValidateDetected(
|
||||
detected_booth,
|
||||
payphone_models,
|
||||
GetEntityCoords(ped),
|
||||
Config.Payphones.ServerValidationDistance
|
||||
)
|
||||
if not location then
|
||||
@@ -1129,7 +1118,7 @@ Bridge.Callbacks.Register("sky_phone:payphone:dial", function(source, data)
|
||||
if not Config.Payphones.Enabled or not SkyPhone.AllowOperation(source, "payphone_dial", 15, 60) then
|
||||
return { success = false, error = "rate_limited" }
|
||||
end
|
||||
local booth_coords, booth_model = valid_payphone_position(source)
|
||||
local booth_coords, booth_model = valid_payphone_position(source, data)
|
||||
if not booth_coords then
|
||||
return { success = false, error = "invalid_payphone" }
|
||||
end
|
||||
|
||||
@@ -12,7 +12,8 @@ end
|
||||
|
||||
local function normalize_coordinates(value, allow_vector)
|
||||
local value_type = type(value)
|
||||
if value_type ~= "table" and (not allow_vector or value_type ~= "vector3") then
|
||||
local supported_vector = value_type == "vector3" or value_type == "vector4"
|
||||
if value_type ~= "table" and (not allow_vector or not supported_vector) then
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -46,60 +47,24 @@ local function normalize_location(location, allowed_models)
|
||||
}
|
||||
end
|
||||
|
||||
function SkyPhonePayphones.ValidateLocations(locations, allowed_models)
|
||||
if type(locations) ~= "table" or type(allowed_models) ~= "table" then
|
||||
return {}, 0
|
||||
end
|
||||
|
||||
local validated = {}
|
||||
local rejected = 0
|
||||
for index, location in pairs(locations) do
|
||||
local valid_index = type(index) == "number" and index >= 1 and index % 1 == 0
|
||||
local normalized = valid_index and normalize_location(location, allowed_models) or nil
|
||||
if normalized then
|
||||
normalized.index = index
|
||||
validated[#validated + 1] = normalized
|
||||
else
|
||||
rejected = rejected + 1
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(validated, function(left, right)
|
||||
return left.index < right.index
|
||||
end)
|
||||
for index = 1, #validated do
|
||||
validated[index].index = nil
|
||||
end
|
||||
|
||||
return validated, rejected
|
||||
end
|
||||
|
||||
function SkyPhonePayphones.FindNearest(locations, player_coords, maximum_distance)
|
||||
if type(locations) ~= "table" then
|
||||
function SkyPhonePayphones.ValidateDetected(location, allowed_models, player_coords, maximum_distance)
|
||||
if type(allowed_models) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
|
||||
local normalized = normalize_location(location, allowed_models)
|
||||
local coords = normalize_coordinates(player_coords, true)
|
||||
local distance = finite_number(maximum_distance)
|
||||
if not coords or not distance or distance <= 0 then
|
||||
if not normalized or not coords or not distance or distance <= 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
local nearest = nil
|
||||
local nearest_distance_squared = distance * distance
|
||||
for index = 1, #locations do
|
||||
local location = locations[index]
|
||||
if type(location) == "table" and type(location.coords) == "table" then
|
||||
local dx = coords.x - location.coords.x
|
||||
local dy = coords.y - location.coords.y
|
||||
local dz = coords.z - location.coords.z
|
||||
local distance_squared = dx * dx + dy * dy + dz * dz
|
||||
if distance_squared <= nearest_distance_squared then
|
||||
nearest = location
|
||||
nearest_distance_squared = distance_squared
|
||||
end
|
||||
end
|
||||
local dx = coords.x - normalized.coords.x
|
||||
local dy = coords.y - normalized.coords.y
|
||||
local dz = coords.z - normalized.coords.z
|
||||
if dx * dx + dy * dy + dz * dz > distance * distance then
|
||||
return nil
|
||||
end
|
||||
|
||||
return nearest
|
||||
return normalized
|
||||
end
|
||||
|
||||
+29
-23
@@ -5,35 +5,41 @@ local allowed_models = {
|
||||
prop_phonebox_04 = true,
|
||||
}
|
||||
|
||||
local locations, rejected = SkyPhonePayphones.ValidateLocations({
|
||||
local detected = SkyPhonePayphones.ValidateDetected(
|
||||
{ model = "prop_phonebox_01a", coords = { x = 100.0, y = 200.0, z = 30.0 } },
|
||||
{ model = "prop_phonebox_04", coords = { x = 105.0, y = 200.0, z = 30.0 } },
|
||||
{ model = "not_allowed", coords = { x = 100.0, y = 200.0, z = 30.0 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = "100", y = 200.0, z = 30.0 } },
|
||||
{ model = "prop_phonebox_01a", coords = { x = 10001.0, y = 200.0, z = 30.0 } },
|
||||
"malformed",
|
||||
}, allowed_models)
|
||||
|
||||
assert(#locations == 2, "only strictly valid configured locations must be accepted")
|
||||
assert(rejected == 4, "every malformed or disallowed configured location must be reported")
|
||||
|
||||
local first = SkyPhonePayphones.FindNearest(locations, { x = 101.0, y = 200.0, z = 30.0 }, 3.0)
|
||||
assert(first and first.model == "prop_phonebox_01a", "nearest configured booth must be selected")
|
||||
|
||||
local second = SkyPhonePayphones.FindNearest(locations, { x = 104.0, y = 200.0, z = 30.0 }, 3.0)
|
||||
assert(second and second.model == "prop_phonebox_04", "another configured booth must be selected by proximity")
|
||||
allowed_models,
|
||||
{ x = 101.0, y = 200.0, z = 30.0 },
|
||||
3.0
|
||||
)
|
||||
assert(detected and detected.model == "prop_phonebox_01a", "a nearby detected booth must be accepted")
|
||||
assert(detected.coords.x == 100.0, "validated booth coordinates must be preserved")
|
||||
|
||||
assert(
|
||||
not SkyPhonePayphones.FindNearest(locations, { x = 0.0, y = 0.0, z = 0.0 }, 3.0),
|
||||
"a player away from every configured booth must be rejected"
|
||||
not SkyPhonePayphones.ValidateDetected(
|
||||
{ model = "not_allowed", coords = { x = 100.0, y = 200.0, z = 30.0 } },
|
||||
allowed_models,
|
||||
{ x = 101.0, y = 200.0, z = 30.0 },
|
||||
3.0
|
||||
),
|
||||
"a detected booth with a disallowed model must be rejected"
|
||||
)
|
||||
assert(
|
||||
not SkyPhonePayphones.FindNearest(locations, { x = "100", y = 200.0, z = 30.0 }, 3.0),
|
||||
"malformed player coordinates must be rejected"
|
||||
not SkyPhonePayphones.ValidateDetected(
|
||||
{ model = "prop_phonebox_01a", coords = { x = "100", y = 200.0, z = 30.0 } },
|
||||
allowed_models,
|
||||
{ x = 101.0, y = 200.0, z = 30.0 },
|
||||
3.0
|
||||
),
|
||||
"malformed detected booth coordinates must be rejected"
|
||||
)
|
||||
assert(
|
||||
not SkyPhonePayphones.FindNearest(locations, { x = 100.0, y = 200.0, z = 30.0 }, 0.0),
|
||||
"an invalid validation distance must be rejected"
|
||||
not SkyPhonePayphones.ValidateDetected(
|
||||
{ model = "prop_phonebox_01a", coords = { x = 100.0, y = 200.0, z = 30.0 } },
|
||||
allowed_models,
|
||||
{ x = 110.0, y = 200.0, z = 30.0 },
|
||||
3.0
|
||||
),
|
||||
"a player away from the detected booth must be rejected"
|
||||
)
|
||||
|
||||
print("Server payphone validation tests passed")
|
||||
print("Detected payphone validation tests passed")
|
||||
|
||||
Reference in New Issue
Block a user