Skip to content

Commit

Permalink
Data download script (for task purpose) (#9)
Browse files Browse the repository at this point in the history
* Initial version of task_download component

Some TODOs in the loop, but might not be needed at this moment

* Add new HEMTT and .gitignore

* Show 0% and 100% progress instead of skipping them

* Add action to check download status

* Complete download when player checks status once done

* Add ace_interact_menu as dependency

* Fix return type

* Borrow display progress on screen from Theseus Mods

* Add display of estimated time left and decrease interval to 1 s

* Apply suggestions from code review

Co-authored-by: Filip Maciejewski <[email protected]>

* Simplify this

* Last tweaks

* Cleanup

* Terminal lines fixes

* Drop random date time

* Last cleanup

* Delete unused stringtable entries

* Update README

* Bump required arma version

* Fix missing public variable

* Rename _texureSource to _textureSelection

It's a hidden selection index or name.

* Better handling for object deletion

If we default the unplug value to true but set it on the server during init then `true` will be returned for objNull and this will prevent infinite loop.

* Add unplugged log

* Apply suggestions from code review

* Update example

* README example update

---------

Co-authored-by: Filip Maciejewski <[email protected]>
  • Loading branch information
3Mydlo3 and veteran29 authored Feb 20, 2024
1 parent 51d5d1f commit 41cb352
Show file tree
Hide file tree
Showing 23 changed files with 750 additions and 3 deletions.
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# Build output
addons/*.pbo
/.hemttout/

# Releases
releases/*
/releases/

hemtt
hemtt.exe
.hemtt/local
symbols/*

# Bikey
Expand Down
85 changes: 85 additions & 0 deletions .hemtt/project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@

name = "ArmaForces Mission Framework"
mainprefix = "z"
prefix = "afmf"

[files]
include = [
"LICENSE",
"mod.cpp",
"README.md"
]

exclude = ["*.psd", "*.png", "*.tga"]

[properties]
author = "ArmaForces"

[version]
path = "addons/main/script_version.hpp"

# Unused in HEMTT v1.11 or higher, kept for backwards compatibility
[asc]
exclude = [
".inc.sqf",
]

[hemtt.launch]
workshop = [
"450814997", # CBA_A3
"2369477168", # ADT
]
parameters = [
"-name=dev",
"-window",
]

[hemtt.launch.ace]
workshop = [
"450814997", # CBA_A3
"2369477168", # ADT
"463939057", # ACE
# "766491311", # KKA3 ACE Extension
]
parameters = [
"-name=dev",
"-window",
]

[hemtt.launch.cup]
workshop = [
"450814997", # CBA_A3
"2369477168", # ADT
"583496184", # CUP Terrains - Core
"583544987", # CUP Terrains - Maps
]
parameters = [
"-name=dev",
"-window",
]

[hemtt.launch.vn]
workshop = [
"450814997", # CBA_A3
"2369477168", # ADT
]
parameters = [
"-name=dev",
"-window",
]
dlc = [
"S.O.G. Prairie Fire",
]

[hemtt.launch.ww2]
workshop = [
"450814997", # CBA_A3
"2369477168", # ADT
]
parameters = [
"-name=dev",
"-window",
]
dlc = [
"Spearhead 1944",
]
2 changes: 1 addition & 1 deletion addons/main/script_mod.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#define VERSION_STR MAJOR.MINOR.PATCH
#define VERSION_AR MAJOR,MINOR,PATCH

#define REQUIRED_VERSION 1.94
#define REQUIRED_VERSION 2.14

#ifdef COMPONENT_BEAUTIFIED
#define COMPONENT_NAME QUOTE(AFMF - COMPONENT_BEAUTIFIED)
Expand Down
1 change: 1 addition & 0 deletions addons/task_download/$PBOPREFIX$
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
z\afmf\addons\task_download
15 changes: 15 additions & 0 deletions addons/task_download/CfgEventHandlers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart));
};
};
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};
class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_postInit));
};
};
42 changes: 42 additions & 0 deletions addons/task_download/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Task Download

A simple script that tracks "download" of some data and publishes event on success and failure, that can be used e.g., in Tasks Framework for completing or failing tasks.

## Setup

```SQF
private _downloadTime = 900; // In seconds
private _downloadSize = 3.42; // In GB
private _result = [laptop, _downloadTime, _downloadSize] call afmf_task_download_fnc_setupSimple;
```

## Settings

For now there are no CBA Settings, but you can easily change some things via variables below if you'd like a different behaviour.

```SQF
// Display refresh interval. Changing it after setup won't work correctly.
afmf_task_download_displayProgressOnScreenRefreshInterval = 1;
```

_Note that this might be changed at some point to proper CBA Settings._

## Events

_Global events:_

- `afmf_task_download_started`
- `afmf_task_download_paused` **Not implemented**
- `afmf_task_download_resumed` **Not implemented**
- `afmf_task_download_successful`
- `afmf_task_download_failed`

_Server side events:_

- `afmf_task_download_start`

## Authors

- [3Mydlo3](http://github.com/3Mydlo3)
- [Mike](https://github.com/Mike-MF)
- [Jonpas](https://github.com/jonpas)
9 changes: 9 additions & 0 deletions addons/task_download/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
PREP(canContinue);
PREP(displayProgressOnScreen);
PREP(formatEstimatedTimeRemaining);
PREP(formatProgress);
PREP(initDownloadAction);
PREP(initGetDeviceAction);
PREP(prepareDisplay);
PREP(setupSimple);
PREP(start);
27 changes: 27 additions & 0 deletions addons/task_download/XEH_postInit.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "script_component.hpp"

if (isServer) then {
[QGVAR(start), FUNC(start)] call CBA_fnc_addEventHandler;

[QGVAR(deviceUnplugged), {
params ["_object"];

_object setVariable [QGVAR(deviceUnplugged), true, true];
[QGVAR(successful), [_object]] call CBA_fnc_globalEvent;
}] call CBA_fnc_addEventHandler;

[QGVAR(successful), {
["ocap_customEvent", ["generalEvent", "Intel was downloaded!"]] call CBA_fnc_serverEvent;
}] call CBA_fnc_addEventHandler;
};

if (hasInterface) then {
[QGVAR(failed), {
systemChat LLSTRING(Failed);
}] call CBA_fnc_addEventHandler;

[QGVAR(startFailed), {
params ["_msg"];
systemChat (_msg call BIS_fnc_localize);
}] call CBA_fnc_addEventHandler;
};
11 changes: 11 additions & 0 deletions addons/task_download/XEH_preInit.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "script_component.hpp"
ADDON = false;

PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;

// Display refresh interval. Changing it after setup won't work correctly.
GVAR(displayProgressOnScreenRefreshInterval) = PROGRESS_INTERVAL;

ADDON = true;
2 changes: 2 additions & 0 deletions addons/task_download/XEH_preStart.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"
20 changes: 20 additions & 0 deletions addons/task_download/config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "script_component.hpp"

class CfgPatches {
class ADDON {
name = COMPONENT_NAME;
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {
"afmf_main",
"ace_interact_menu"
};
skipWhenMissingDependencies = 1;
author = "ArmaForces";
authors[] = {"3Mydlo3"};
VERSION_CONFIG;
};
};

#include "CfgEventHandlers.hpp"
20 changes: 20 additions & 0 deletions addons/task_download/functions/fnc_canContinue.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "script_component.hpp"
/*
* Author: 3Mydlo3
* Function checks if download from given object can continue.
*
* Arguments:
* 0: Object which is used for download <OBJECT>
*
* Return Value:
* True if download can continue <BOOL>
*
* Example:
* [laptop] call afmf_task_download_fnc_canContinue
*
* Public: No
*/

params [["_object", objNull]];

alive _object // return
118 changes: 118 additions & 0 deletions addons/task_download/functions/fnc_displayProgressOnScreen.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#include "script_component.hpp"
/*
* Author: Mike, Jonpas from Theseus Mods; 3Mydlo3
* Only Laptop, Rugged Laptop & PC Set - Screen are actively supported.
* Has a laptop generate an intel download after an ACE interaction.
* Texture source is shown on the object via Attributes > Object Specific > Texture #X
*
* Further adjusted by 3Mydlo3
*
* Arguments:
* 0: PFH Args <ARRAY>
* 0: Last refresh time <NUMBER>
* 1: Current terminal content <ARRAY>
* 2: Object used for download <OBJECT>
* 3: Total file size (in GB) to download <NUMBER>
* 4: Texture source <NUMBER>
* 5: Download tick rate <NUMBER>
* 6: Pending terminal prepare steps <ARRAY>
* 1: PFH Handle <NUMBER>
*
* Return Value:
* None
*
* Example:
* None
*
* Public: No
*/

params ["_args", "_handle"];
_args params ["_lastTime", "_terminal", "_object", "_fileSize", "_textureSelection", "_downloadTime", "_terminalPrepare"];

// Exit if download hasn't yet started
if !(_object getVariable [QGVAR(downloadStarted), false]) exitWith {};

private _prepareFinished = _object getVariable [QGVAR(downloadIntel_prepareFinished_client), false];

// Prepare
if (!_prepareFinished) exitWith {
// 2s tick rate
if (_lastTime + PREPARATION_INTERVAL > CBA_missionTime) exitWith {};
_args set [0, CBA_missionTime];

private _prepareStage = _object getVariable [QGVAR(downloadIntel_prepareStage_client), 0];

_terminal deleteAt (count _terminal - 1);
_terminal append (_terminalPrepare select _prepareStage);

private _texture = format ['#(rgb,512,512,3)text(0,0,"EtelkaMonospacePro",0.03,"#1A1818","#00B200","%1")', _terminal joinString "\n"];
_object setObjectTexture [_textureSelection, _texture];
_object setVariable [QGVAR(downloadIntel_prepareStage_client), _prepareStage + 1];

if (_prepareStage + 1 >= count _terminalPrepare) then {
_object setVariable [QGVAR(downloadIntel_prepareFinished_client), true];
};
};

// Follow wanted download (tick) rate from here
if (_lastTime + _downloadTime > CBA_missionTime) exitWith {};
_args set [0, CBA_missionTime];

// Show download progress
private _downloadStartTime = _object getVariable [QGVAR(downloadStartTime), 0];
private _progressPerTick = _object getVariable [QGVAR(downloadProgressPerTick), MAX_PROGRESS];
private _currentProgress = (CBA_missionTime - _downloadStartTime)/PROGRESS_INTERVAL * _progressPerTick max 0 min MAX_PROGRESS;

private _progressBarStages = floor (_currentProgress / 10);
private _downloaded = _fileSize * (_currentProgress / 100);
private _progressBar = "[ ]";
for "_i" from 1 to _progressBarStages do {
_progressBar = _progressBar splitString "";
_progressBar set [_i, "="];
_progressBar = _progressBar joinString "";
};

private _progressString = format [" %1GB / %2GB %3 (%4)\n", _downloaded, _fileSize, _progressBar, [_currentProgress] call FUNC(formatProgress)];
_terminal set [-3, _progressString];

// Set time display
private _totalDownloadTime = _object getVariable [QGVAR(downloadTime), 0];
private _timeText = if (_currentProgress isEqualTo MAX_PROGRESS) then {
format [" Download completed in: %1", [_totalDownloadTime] call CBA_fnc_formatElapsedTime]
} else {
private _estimatedTimeLeft = [_totalDownloadTime, _currentProgress] call FUNC(formatEstimatedTimeRemaining);
format [" Estimated time left: %1", _estimatedTimeLeft]
};

_terminal set [-1, _timeText];

_texture = format ['#(rgb,512,512,3)text(0,0,"EtelkaMonospacePro",0.03,"#1A1818","#00B200","%1")', _terminal joinString "\n"];
_object setObjectTexture [_textureSelection, _texture];

// Finish
if (_currentProgress isEqualTo MAX_PROGRESS) exitWith {
_handle call CBA_fnc_removePerFrameHandler;

private _terminalFinal = [
" Wiping...",
" Remove Device!"
];
_terminal append _terminalFinal;
_texture = format ['#(rgb,512,512,3)text(0,0,"EtelkaMonospacePro",0.03,"#1A1818","#00B200","%1")', _terminal joinString "\n"];
_object setObjectTexture [_textureSelection, _texture];

[{(_this select 0) getVariable [QGVAR(deviceUnplugged), true]}, {
params ["_object", "_terminal", "_textureSelection"];
INFO_1("Device unplugged %1",_object);

private _terminalDeviceUnplugged = [
"",
" Device unplugged!"
];

_terminal append _terminalDeviceUnplugged;
_texture = format ['#(rgb,512,512,3)text(0,0,"EtelkaMonospacePro",0.03,"#1A1818","#00B200","%1")', _terminal joinString "\n"];
_object setObjectTexture [_textureSelection, _texture];
}, [_object, _terminal, _textureSelection]] call CBA_fnc_waitUntilAndExecute;
};
Loading

0 comments on commit 41cb352

Please sign in to comment.