Merge pull request #1772 from FlightControl-Master/FF/Ops

SOCKET
This commit is contained in:
Frank 2022-09-01 22:44:43 +02:00 committed by GitHub
commit 85eca4c464
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 316 additions and 190332 deletions

View File

@ -1,24 +0,0 @@
env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' )
local base = _G
__Moose = {}
__Moose.Include = function( IncludeFile )
if not __Moose.Includes[ IncludeFile ] then
__Moose.Includes[IncludeFile] = IncludeFile
local f = assert( base.loadfile( IncludeFile ) )
if f == nil then
error ("Moose: Could not load Moose file " .. IncludeFile )
else
env.info( "Moose: " .. IncludeFile .. " dynamically loaded." )
return f()
end
end
end
__Moose.Includes = {}
__Moose.Include( 'Scripts/Moose/Modules.lua' )
BASE:TraceOnOff( true )
env.info( '*** MOOSE INCLUDE END *** ' )

File diff suppressed because it is too large Load Diff

View File

@ -429,6 +429,11 @@ RANGE.TargetType = {
-- @field #string airframe Aircraft type of player.
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
-- @field #string date OS date.
-- @field #number attackHdg Attack heading in degrees.
-- @field #number attackVel Attack velocity in knots.
-- @field #number attackAlt Attack altitude in feet.
-- @field #string clock Time of the run.
-- @field #string rangename Name of the range.
--- Strafe result.
-- @type RANGE.StrafeResult
@ -436,6 +441,13 @@ RANGE.TargetType = {
-- @field #string airframe Aircraft type of player.
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
-- @field #string date OS date.
-- @field #string name Name of the target pit.
-- @field #number roundsFired Number of rounds fired.
-- @field #number roundsHit Number of rounds that hit the target.
-- @field #number strafeAccuracy Accuracy of the run in percent.
-- @field #string clock Time of the run.
-- @field #string rangename Name of the range.
-- @field #boolean invalid Invalid pass.
--- Sound file data.
-- @type RANGE.Soundfile
@ -569,17 +581,16 @@ RANGE.version = "2.4.0"
--- RANGE contructor. Creates a new RANGE object.
-- @param #RANGE self
-- @param #string rangename Name of the range. Has to be unique. Will we used to create F10 menu items etc.
-- @param #string RangeName Name of the range. Has to be unique. Will we used to create F10 menu items etc.
-- @return #RANGE RANGE object.
function RANGE:New( rangename )
BASE:F( { rangename = rangename } )
function RANGE:New( RangeName )
-- Inherit BASE.
local self = BASE:Inherit( self, FSM:New() ) -- #RANGE
-- Get range name.
-- TODO: make sure that the range name is not given twice. This would lead to problems in the F10 radio menu.
self.rangename = rangename or "Practice Range"
self.rangename = RangeName or "Practice Range"
-- Log id.
self.id = string.format( "RANGE %s | ", self.rangename )
@ -950,6 +961,19 @@ function RANGE:SetTargetSheet( path, prefix )
return self
end
--- Set FunkMan socket. Bombing and strafing results will be send to your Discord bot.
-- **Requires running FunkMan program**.
-- @param #RANGE self
-- @param #number Port Port. Default `10042`.
-- @param #string Host Host. Default "127.0.0.1".
-- @return #RANGE self
function RANGE:SetFunkManOn(Port, Host)
self.funkmanSocket=SOCKET:New(Port, Host)
return self
end
--- Set messages to examiner. The examiner will receive messages from all clients.
-- @param #RANGE self
-- @param #string examinergroupname Name of the group of the examiner.
@ -1728,7 +1752,6 @@ function RANGE:OnEventHit( EventData )
self:_DisplayMessageToGroup( _unit, text )
self:T2( self.id .. text )
_currentTarget.pastfoulline = true
invalidStrafe = true -- Rangeboss Edit
end
end
@ -1760,6 +1783,13 @@ function RANGE:OnEventHit( EventData )
end
end
--- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun).
-- @param #RANGE self
-- @param #table weapon Weapon
function RANGE:_TrackWeapon(weapon)
end
--- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun).
-- @param #RANGE self
-- @param Core.Event#EVENTDATA EventData
@ -1806,6 +1836,11 @@ function RANGE:OnEventShot( EventData )
-- Get player unit and name.
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
-- Attack parameters.
local attackHdg=_unit:GetHeading()
local attackAlt=_unit:GetHeight()
local attackVel=_unit:GetVelocityKNOTS()
-- Set this to larger value than the threshold.
local dPR = self.BombtrackThreshold * 2
@ -1848,7 +1883,6 @@ function RANGE:OnEventShot( EventData )
-- Check again in ~0.005 seconds ==> 200 checks per second.
return timer.getTime() + self.dtBombtrack
else
-----------------------------
@ -1858,7 +1892,7 @@ function RANGE:OnEventShot( EventData )
-- Get closet target to last position.
local _closetTarget = nil -- #RANGE.BombTarget
local _distance = nil
local _closeCoord = nil
local _closeCoord = nil --Core.Point#COORDINATE
local _hitquality = "POOR"
-- Get callsign.
@ -1886,6 +1920,7 @@ function RANGE:OnEventShot( EventData )
-- Loop over defined bombing targets.
for _, _bombtarget in pairs( self.bombingTargets ) do
local bombtarget=_bombtarget --#RANGE.BombTarget
-- Get target coordinate.
local targetcoord = self:_GetBombTargetCoordinate( _bombtarget )
@ -1898,15 +1933,15 @@ function RANGE:OnEventShot( EventData )
-- Find closest target to last known position of the bomb.
if _distance == nil or _temp < _distance then
_distance = _temp
_closetTarget = _bombtarget
_closeCoord = targetcoord
_closetTarget = bombtarget
_closeCoord = targetcoord
if _distance <= 1.53 then -- Rangeboss Edit
_hitquality = "SHACK" -- Rangeboss Edit
elseif _distance <= 0.5 * _bombtarget.goodhitrange then -- Rangeboss Edit
elseif _distance <= 0.5 * bombtarget.goodhitrange then -- Rangeboss Edit
_hitquality = "EXCELLENT"
elseif _distance <= _bombtarget.goodhitrange then
elseif _distance <= bombtarget.goodhitrange then
_hitquality = "GOOD"
elseif _distance <= 2 * _bombtarget.goodhitrange then
elseif _distance <= 2 * bombtarget.goodhitrange then
_hitquality = "INEFFECTIVE"
else
_hitquality = "POOR"
@ -1927,6 +1962,7 @@ function RANGE:OnEventShot( EventData )
local _results = self.bombPlayerResults[_playername]
local result = {} -- #RANGE.BombResult
result.command=SOCKET.DataType.BOMBRESULT
result.name = _closetTarget.name or "unknown"
result.distance = _distance
result.radial = _closeCoord:HeadingTo( impactcoord )
@ -1934,11 +1970,17 @@ function RANGE:OnEventShot( EventData )
result.quality = _hitquality
result.player = playerData.playername
result.time = timer.getAbsTime()
result.clock = UTILS.SecondsToClock(result.time, true)
result.midate = UTILS.GetDCSMissionDate()
result.theatre = env.mission.theatre
result.airframe = playerData.airframe
result.roundsFired = 0 -- Rangeboss Edit
result.roundsHit = 0 -- Rangeboss Edit
result.roundsQuality = "N/A" -- Rangeboss Edit
result.rangename = self.rangename
result.attackHdg = attackHdg
result.attackVel = attackVel
result.attackAlt = attackAlt
-- Add to table.
table.insert( _results, result )
@ -2078,13 +2120,13 @@ function RANGE:onafterImpact( From, Event, To, result, player )
-- Only display target name if there is more than one bomb target.
local targetname = nil
if #self.bombingTargets > 1 then
local targetname = result.name
targetname = result.name
end
-- Send message to player.
local text = string.format( "%s, impact %03d° for %d ft", player.playername, result.radial, UTILS.MetersToFeet( result.distance ) )
if targetname then
text = text .. string.format( " from bulls of target %s." )
text = text .. string.format( " from bulls of target %s.", targetname )
else
text = text .. "."
end
@ -2110,16 +2152,40 @@ function RANGE:onafterImpact( From, Event, To, result, player )
end
-- Unit.
local unit = UNIT:FindByName( player.unitname )
-- Send message.
self:_DisplayMessageToGroup( unit, text, nil, true )
self:T( self.id .. text )
if player.unitname then
-- Get unit.
local unit = UNIT:FindByName( player.unitname )
-- Send message.
self:_DisplayMessageToGroup( unit, text, nil, true )
self:T( self.id .. text )
end
-- Save results.
if self.autosave then
self:Save()
end
-- Send result to FunkMan, which creates fancy MatLab figures and sends them to Discord via a bot.
if self.funkmanSocket then
self.funkmanSocket:SendTable(result)
end
end
--- Function called after strafing run.
-- @param #RANGE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #RANGE.PlayerData player Player data table.
-- @param #RANGE.StrafeResult result Result of run.
function RANGE:onafterStrafeResult( From, Event, To, player, result)
if self.funkmanSocket then
self.funkmanSocket:SendTable(result)
end
end
@ -2175,7 +2241,7 @@ function RANGE:onafterSave( From, Event, To )
local target = result.name
local radial = result.radial
local quality = result.quality
local time = UTILS.SecondsToClock( result.time )
local time = UTILS.SecondsToClock(result.time, true)
local airframe = result.airframe
local date = "n/a"
if os then
@ -3046,9 +3112,13 @@ function RANGE:_CheckInZone( _unitName )
-- Strafe result.
local result = {} -- #RANGE.StrafeResult
result.command=SOCKET.DataType.STRAFERESULT
result.player=_playername
result.name=_result.zone.name or "unknown"
result.time = timer.getAbsTime()
result.clock = UTILS.SecondsToClock(result.time)
result.midate = UTILS.GetDCSMissionDate()
result.theatre = env.mission.theatre
result.roundsFired = shots
result.roundsHit = _result.hits
result.roundsQuality = resulttext

View File

@ -5,6 +5,7 @@ __Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/FiFo.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Socket.lua' )
__Moose.Include( 'Scripts/Moose/Core/Base.lua' )
__Moose.Include( 'Scripts/Moose/Core/Beacon.lua' )

View File

@ -3361,6 +3361,20 @@ function AIRBOSS:SetDebugModeOFF()
return self
end
--- Set FunkMan socket. LSO grades and trap sheets will be send to your Discord bot.
-- **Requires running FunkMan program**.
-- @param #AIRBOSS self
-- @param #number Port Port. Default `10042`.
-- @param #string Host Host. Default `"127.0.0.1"`.
-- @return #AIRBOSS self
function AIRBOSS:SetFunkManOn(Port, Host)
self.funkmanSocket=SOCKET:New(Port, Host)
return self
end
--- Get next time the carrier will start recovering aircraft.
-- @param #AIRBOSS self
-- @param #boolean InSeconds If true, abs. mission time seconds is returned. Default is a clock #string.
@ -11273,7 +11287,7 @@ end
--- Get wind speed on carrier deck parallel and perpendicular to runway.
-- @param #AIRBOSS self
-- @param #number alt Altitude in meters. Default 15 m. (change made from 50m from Discord discussion from Sickdog)
-- @param #number alt Altitude in meters. Default 18 m.
-- @return #number Wind component parallel to runway im m/s.
-- @return #number Wind component perpendicular to runway in m/s.
-- @return #number Total wind strength in m/s.
@ -11296,7 +11310,7 @@ function AIRBOSS:GetWindOnDeck( alt )
zc = UTILS.Rotate2D( zc, -self.carrierparam.rwyangle )
-- Wind (from) vector
local vw = cv:GetWindWithTurbulenceVec3( alt or 15 )
local vw = cv:GetWindWithTurbulenceVec3( alt or 18 ) --(change made from 50m to 15m from Discord discussion from Sickdog, next change to 18m due to SC higher deck discord)
-- Total wind velocity vector.
-- Carrier velocity has to be negative. If carrier drives in the direction the wind is blowing from, we have less wind in total.
@ -12781,19 +12795,23 @@ function AIRBOSS:_Debrief( playerData )
end
mygrade.case = playerData.case
local windondeck = self:GetWindOnDeck()
mygrade.wind = tostring( UTILS.Round( UTILS.MpsToKnots( windondeck ), 1 ) )
mygrade.wind = UTILS.Round( UTILS.MpsToKnots( windondeck ), 1 )
mygrade.modex = playerData.onboard
mygrade.airframe = playerData.actype
mygrade.carriertype = self.carriertype
mygrade.carriername = self.alias
mygrade.carrierrwy = self.carrierparam.rwyangle
mygrade.theatre = self.theatre
mygrade.mitime = UTILS.SecondsToClock( timer.getAbsTime() )
mygrade.mitime = UTILS.SecondsToClock( timer.getAbsTime(), true )
mygrade.midate = UTILS.GetDCSMissionDate()
mygrade.osdate = "n/a"
if os then
mygrade.osdate = os.date() -- os.date("%d.%m.%Y")
end
-- Add last grade to playerdata for FunkMan.
playerData.grade=mygrade
-- Save trap sheet.
if playerData.trapon and self.trapsheet then
self:_SaveTrapSheet( playerData, mygrade )
@ -17909,6 +17927,58 @@ function AIRBOSS:onafterLoad( From, Event, To, path, filename )
end
--- On after "LSOGrade" event.
-- @param #AIRBOSS self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AIRBOSS.PlayerData playerData Player Data.
-- @param #AIRBOSS.LSOgrade grade LSO grade.
function AIRBOSS:onafterLSOGrade(From, Event, To, playerData, grade)
if self.funkmanSocket then
-- Extract used info for FunkMan. We need to be careful with the amount of data send via UDP socket.
local trapsheet={} ; trapsheet.X={} ; trapsheet.Z={} ; trapsheet.AoA={} ; trapsheet.Alt={}
-- Loop over trapsheet and extract used values.
for i = 1, #playerData.trapsheet do
local ts=playerData.trapsheet[i] --#AIRBOSS.GrooveData
table.insert(trapsheet.X, UTILS.Round(ts.X, 1))
table.insert(trapsheet.Z, UTILS.Round(ts.Z, 1))
table.insert(trapsheet.AoA, UTILS.Round(ts.AoA, 2))
table.insert(trapsheet.Alt, UTILS.Round(ts.Alt, 1))
end
local result={}
result.command=SOCKET.DataType.LSOGRADE
result.name=playerData.name
result.trapsheet=trapsheet
result.airframe=grade.airframe
result.mitime=grade.mitime
result.midate=grade.midate
result.wind=grade.wind
result.carriertype=grade.carriertype
result.carriername=grade.carriername
result.carrierrwy=grade.carrierrwy
result.theatre=grade.theatre
result.case=playerData.case
result.Tgroove=grade.Tgroove
result.wire=grade.wire
result.grade=grade.grade
result.points=grade.points
result.details=grade.details
-- Debug info.
self:T(self.lid.."Result onafterLSOGrade")
self:T(result)
-- Send result.
self.funkmanSocket:SendTable(result)
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,150 @@
--- **Utilities** - Socket.
--
-- **Main Features:**
--
-- * Sockets
-- * Send messages to Discord
--
-- ===
--
-- ### Author: **funkyfranky**
-- @module Utilities.Socket
-- @image Utilities_Socket.png
--- SOCKET class.
-- @type SOCKET
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity level.
-- @field #string lid Class id string for output to DCS log file.
-- @field #table socket The socket.
-- @field #number port The port.
-- @field #string host The host.
-- @field #table json JSON.
-- @extends Core.Fsm#FSM
--- **At times I feel like a socket that remembers its tooth.** -- Saul Bellow
--
-- ===
--
-- # The SOCKET Concept
--
-- Create a UDP socket server. It enables you to send messages to discord servers via discord bots.
--
-- **Note** that you have to **de-sanitize** `require` and `package` in your `MissionScripting.lua` file, which is in your `DCS/Scripts` folder.
--
--
-- @field #SOCKET
SOCKET = {
ClassName = "SOCKET",
verbose = 0,
lid = nil,
}
--- Data type. This is the keyword the socket listener uses.
-- @field #string TEXT Plain text.
-- @field #string BOMBRESULT Range bombing.
-- @field #string STRAFERESULT Range strafeing result.
-- @field #string LSOGRADE Airboss LSO grade.
SOCKET.DataType={
TEXT="moose_text",
BOMBRESULT="moose_bomb_result",
STRAFERESULT="moose_strafe_result",
LSOGRADE="moose_lso_grade",
}
--- SOCKET class version.
-- @field #string version
SOCKET.version="0.1.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot!
-- TODO: Messages as spoiler.
-- TODO: Send images?
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new SOCKET object.
-- @param #SOCKET self
-- @param #number Port UDP port. Default `10042`.
-- @param #string Host Host. Default `"127.0.0.1"`.
-- @return #SOCKET self
function SOCKET:New(Port, Host)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) --#SOCKET
package.path = package.path..";.\\LuaSocket\\?.lua;"
package.cpath = package.cpath..";.\\LuaSocket\\?.dll;"
self.socket = require("socket")
self.port=Port or 10042
self.host=Host or "127.0.0.1"
self.json=loadfile("Scripts\\JSON.lua")()
self.UDPSendSocket=self.socket.udp()
self.UDPSendSocket:settimeout(0)
return self
end
--- Set port.
-- @param #SOCKET self
-- @param #number Port Port. Default 10042.
-- @return #SOCKET self
function SOCKET:SetPort(Port)
self.port=Port or 10042
end
--- Set host.
-- @param #SOCKET self
-- @param #string Host Host. Default `"127.0.0.1"`.
-- @return #SOCKET self
function SOCKET:SetHost(Host)
self.host=Host or "127.0.0.1"
end
--- Send a table.
-- @param #SOCKET self
-- @param #table Table Table to send.
-- @return #SOCKET self
function SOCKET:SendTable(Table)
local json= self.json:encode(Table)
-- Debug info.
self:T("Json table:")
self:T(json)
-- Send data.
self.socket.try(self.UDPSendSocket:sendto(json, self.host, self.port))
return self
end
--- Send a text message.
-- @param #SOCKET self
-- @param #string Text Test message.
-- @return #SOCKET self
function SOCKET:SendText(Text)
local message={}
message.command = SOCKET.DataType.TEXT
message.text = Text
self:SendTable(message)
return self
end

View File

@ -777,8 +777,7 @@ end
--- Returns the POSITIONABLE height above sea level in meters.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Vec3 The height of the positionable.
-- @return #nil The POSITIONABLE is not existing or alive.
-- @return DCS#Vec3 Height of the positionable in meters (or nil, if the object does not exist).
function POSITIONABLE:GetHeight() --R2.1
self:F2( self.PositionableName )