So I have a little sensor in my 'scene' and when it gets blocked I want my program to wait 4 seconds and if the sensor is still blocked I want it to alert the user.
The script works fine if the sensor remains blocked.
However, if you block the sensor for less than the 4 seconds and then remove the part from the sensor (which should result in no alert since the sensor is no longer blocked) the alert still runs even though the condition is no longer true.
Can any buddy see what I am doing wrong here?
The OnBlocked() function runs when the sensor is blocked and the OnCleared() function runs when the sensor is cleared.
The OnisBlockedUpdated() function runs when the isBlocked property is updated.
function OnBlocked( sender : Demo3D.Visuals.PhysicsObject, load : Demo3D.Visuals.Visual )
{
sender.isBlocked = true;
sender.PropertiesUpdated();
}
function OnCleared( sender : Demo3D.Visuals.PhysicsObject, load : Demo3D.Visuals.Visual )
{
sender.isBlocked = false;
sender.PropertiesUpdated();
}
function OnisBlockedUpdated( sender : Demo3D.Visuals.BoxVisual, value : System.Boolean, oldValue )
{
var blockingObj : Demo3D.Visuals.BoxVisual = sender.BlockingLoad;
if (value)
{
print("isBlocked");
wait(4);
sender.PropertiesUpdated();
if(value)
{
alert("The object '" + blockingObj + "' is too tall for this bay.");
}
else
{
return;
}
}
if(!value)
{
print("cleared");
return;
}
}
if you block the sensor for less than the 4 seconds and then remove the part from the sensor (which should result in no alert since the sensor is no longer blocked) the alert still runs even though the condition is no longer true
The function is still running while you're doing your wait(), and the value parameter will be passed in by-value, not by-reference, so it isn't going to change in the middle of the body of the function.
If you want to evaluate that value after the wait has completed, you're going to have to get the current value, rather than the value passed into the function.
Try:
if (value)
{
print("isBlocked");
wait(4);
sender.PropertiesUpdated();
if(sender.isBlocked) // *** This is the line I changed
{
// ...
Although I'm not sure if sender is going to be the same object as in the OnBlocked or OnCleared function, since it is a different type. You may need to figure out some way to get a reference to that same sender : Demo3D.Visuals.PhysicsObject object.
Related
I am new here, but have often benefited from questions and their results.
Now I have a problem that I can not solve for days. It is about a STM32L431RCT6 with FreeRTOS. There are 3 tasks running on it. Two of them are dedicated to processing CanOpenNode (1 to send data, 1 to receive). One is a custom controller. The code works as it is, but when I enable the CRC unit (MX_CRC_Init()) the problem appears. With the CRC unit enabled, only the task to receive the data from Canopen is executed. The other tasks are set to "Ready". What I notice is that the osDelay() used in the receive task seems to be ignored. It doesn't seem to matter if I use osDelay(1) or osDelay(10000).
void start_CO_rec_Thread(void *argument)
{
/* USER CODE BEGIN start_CO_TI_Thread */
/* Infinite loop */
for(;;)
{
canopen_app_interrupt();
osDelay(1);
}
osThreadTerminate(NULL);
/* USER CODE END start_CO_TI_Thread */
}
Something else is added. If I remove functions and variables in the task by starting an own controller, the processing of the tasks works again. Now I have concluded that the tasks need more stack memory. But this is also not the solution of the puzzle...
Working Code:
void Start_Controller(void *argument)
{
Sensor = new DS18B20(htim6);
Regler = new Smithpredictor(Sensor);
// osTimerStart(LifetimerHandle, 1000);
for(;;)
{
if (global_state==4)
actual_Temperatur = Regler->run(target_Temperature);
osDelay(MBC_intervall_s*1000);
}
osThreadTerminate(NULL);
}
Not Working Code:
void Start_Controller(void *argument)
{
Sensor = new DS18B20(htim6);
Regler = new Smithpredictor(Sensor);
osTimerStart(LifetimerHandle, 1000);
for(;;)
{
if (global_state==4)
actual_Temperatur = Regler->run(target_Temperature);
osDelay(MBC_intervall_s*1000);
}
osThreadTerminate(NULL);
}
I hope someone has an idea how to proceed or can help me. Even if it is just another way to further identify the problem. Maybe I have also committed some stupidity, I am unfortunately not a computer scientist.
Hey I need some help here for How to use timeouts in flutter correctly. First of all to explain what the main goal is:
I want to recive data from my Firebase RealTime Database but need to secure this request api call with an time out of 15 sec. So after 15 sec my timeout should throw an exception that will return to the Users frontend the alert for reasons of time out.
So I used the simple way to call timeouts on future functions:
This functions should only check if on some firebase node an ID is existing or not:
Inside this class where I have declared this functions I also have an instance which called : timeoutControl this is a class which contains a duration and some reasons for the exceptions.
Future<bool> isUserCheckedIn(String oid, String maybeCheckedInUserIdentifier, String onGateId) async {
try {
databaseReference = _firebaseDatabase.ref("Boarding").child(oid).child(onGateId);
final snapshot = await databaseReference.get().timeout(Duration(seconds: timeoutControl.durationForTimeOutInSec), onTimeout: () => timeoutControl.onEppTimeoutForTask());
if(snapshot.hasChild(maybeCheckedInUserIdentifier)) {
return true;
}
else {
return false;
}
}
catch (exception) {
return false;
}
}
The TimeOutClass where the instance timeoutControl comes from:
class CustomTimeouts {
int durationForTimeOutInSec = 15; // The seconds for how long to try until we throw an timeout exception
CustomTimeouts();
// TODO: Implement the exception reasons here later ...
onEppTimeoutForUpload() {
throw Exception("Some reason ...");
}
onEppTimeoutForTask() {
throw Exception("Some reason ...");
}
onEppTimeoutForDownload() {
throw Exception("Some reason ...");
}
}
So as you can see for example I tried to use this implementation above. This works fine ... sometimes I need to fight with un explain able things -_-. Let me try to introduce what in somecases are the problem:
Inside the frontend class make this call:
bool isUserCheckedIn = await service.isUserCheckedIn(placeIdentifier, userId, gateId);
Map<String, dynamic> data = {"gateIdActive" : isUserCheckedIn};
/*
The response here is an Custom transaction handler which contains an error or an returned param
etc. so this isn't relevant for you ...
*/
_gateService.updateGate(placeIdentifier, gateId, data).then((response) {
if(response.hasError()) {
setState(() {
EppDialog.showErrorToast(response.getErrorMessage()); // Shows an error message
isSendButtonDiabled = false; /*Reset buttons state*/
});
}
else {
// Create an gate process here ...
createGateEntrys(); // <-- If the closures update was successful we also handle some
// other data inside the RTDB for other reasons here ...
}
});
IMPORTANT to know for you guys is that I am gonna use the returned "boolean" value from this function call to update some other data which will be pushed and uploaded into another RTDB other node location for other reasons. And if this was also successful the application is going on to update some entrys also inside the RTDB -->createGateEntrys()<-- This function is called as the last one and is also marked as an async function and called with its closures context and no await statement.
The Data inside my Firebase RTDB:
"GateCheckIns" / "4mrithabdaofgnL39238nH" (The place identifier) / "NFdxcfadaies45a" (The Gate Identifier)/ "nHz2mhagadzadzgadHjoeua334" : 1 (as top of the key some users id who is checked in)
So on real devices this works always without any problems... But the case of an real device or simulator could not be the reason why I'am faceing with this problem now. Sometimes inside the Simulator this Function returns always false no matter if the currentUsers Identifier is inside the this child nodes or not. Therefore I realized the timeout is always called immediately so right after 1-2 sec because the exception was always one of these I was calling from my CustomTimeouts class and the function which throws the exception inside the .timeout(duration, onTimeout: () => ...) call. I couldn't figure it out because as I said on real devices I was not faceing with this problem.
Hope I was able to explain the problem it's a little bit complicated I know but for me is important that someone could explain me for what should I pay attention to if I am useing timeouts in this style etc.
( This is my first question here on StackOverFlow :) )
My situation is the following:
I developed a game, where people can save their progress via google cloud. I'm releasing big content-updates, resulting in many people returning to my game at the same time, trying to get their savegame.
This overload causing my customers to get stucked in the savegame-loading process - not able to start playing with their progress.
Here's an updated 4 days screenshot of the cloud-api-dashboard
(And here's the old "12 hours" screenshot of the cloud-api-dashboard)
more informations about the Project:
The game keeps using the "save in cloud"-function in the background on some stages of the game to provide players with the functionality to play on two diffrent devices.
I'm using Unity 2019.3.9f1 and the Asset "Easy Mobile Pro 2.17.3" for the Game-Service-Feature.
The "Google Play Games Plugin" has the version "0.10.12" and can be found on github
more informations about the Cloud-Situation:
The OAuth "user type" is "External" (and can't be changed)
The OAuth user cap display shows "0/100" for the user-cap
And The OAuth rate limits is displaying this for the token-grant-rate (highest "Average Token Grant Rate" is 3,33 of 10.000 as limit)
All used quotas are within the limit. The project reaches
1/10 of "queries per day" (1.000.000.000 max) and
1/2 of "queries per 100 sec" (20.000 max).
more informations about the Error-Trace in the cloud-API:
On my search for a better Error-Log I tried to find “Cloud Logging”-tools in the “Google Cloud Platform”-console. But every section i tried won’t display anything:
“Logging” (Operations tool) is empty
“Cloud Logging API” says: “no data available for the selected time frame.”
“Cloud Debugger API” says: “no data available for the selected time frame.”
I can't find a more detailed variant of the errors as this (the "Metrics"-Section in the "Google Drive API"):
Is there anything I miss to get a better insight?
more informations about the Core-Code
As I mentioned, I’m using “EasyMobilePro”, so I have one “SaveGame”-Var and 8 calls for google and apple as well. I already contacted their support: They assured me that those calls are unchangeable & kind of rock solid (so it can’t be caused from their code) and I should try to contact google if the problem is not on my side.
The 5 calls from EasyMobile for cloudsave are:
bool “GameServices.IsInitialized()”
void “GameServices.OpenWithAutomaticConflictResolution”
void “GameServices.WriteSavedGameData”
void “GameServices.ReadSavedGameData”
void “GameServices.DeleteSavedGame”
The 3 calls from EasyMobile for cloud-login are:
void “GameServices.Init()”
delegate “GameServices.UserLoginSucceeded”
delegate “GameServices.UserLoginFailed”
The Process, that causes the Issue:
I call “GameService.Init()”, the user logs in (no problem)
On that “LoginSuccess”-Callback I call my Function “HandleFirstCloudOpening”:
//This Method is Called, after the player Pressed "Save/ Load" on the StartScreen
//The button is disabled imidiately (and will be re-enabled if an error/fail happens)
public void TryCallUserLogin() {
if (!IsLoginInit) {
EasyMobile.GameServices.UserLoginFailed += HandleLoginFail;
EasyMobile.GameServices.UserLoginSucceeded += HandleFirstCloudOpening;
IsLoginInit = true;
}
if (!IsGameServiceInitialized) {
EasyMobile.GameServices.Init();
} else { //This "else" is only be called, if the "Init" was successfull, but the player don't have a connected savegame
HandleFirstCloudOpening();
}
}
private void HandleLoginFail() {
//(...) Show ErrorPopup, let the player try to login again
}
private void HandleFirstCloudOpening() {
if (currentSaveState != CloudSaveState.NONE) {
CloudStateConflictDebug(CloudSaveState.OPENING);
return;
}
currentSaveState = CloudSaveState.OPENING;
EasyMobile.GameServices.SavedGames.OpenWithAutomaticConflictResolution(cloudSaveNameReference, UseFirstTimeOpenedSavedGame);
}
private void UseFirstTimeOpenedSavedGame(EasyMobile.SavedGame _savedGame, string _error) {
currentSaveState = CloudSaveState.NONE;
if (string.IsNullOrEmpty(_error)) {
cloudSaveGame = _savedGame;
ReadDataFromCloud(cloudSaveGame);
} else {
ErrorPopupWithCloseButton("cloud_open", "failed with error: " + _error);
}
}
private void ReadDataFromCloud(EasyMobile.SavedGame _savedGame) {
if (_savedGame.IsOpen) {
currentSaveState = CloudSaveState.LOADING;
EasyMobile.GameServices.SavedGames.ReadSavedGameData(_savedGame, UseSucessfullLoadedCloudSaveGame);
} else { //backup function if the fresh-opened savegame is "closed" for some reason (can happen later while "saving" ingame)
HandleFirstCloudOpening();
}
}
private void UseSucessfullLoadedCloudSaveGame(EasyMobile.SavedGame _game, byte[] _cloudData, string error) {
if (!string.IsNullOrEmpty(error)) {
ErrorPopupWithCloseButton("cloud_read", "Reading saved game data failed: " + error);
return;
}
if (_cloudData.Length > 0) {
//A function, that converts the saved bytes to my useable Savegame-Data
//having a "try&catch": if it fails, it useses the callback with the param "null"
SaveGameToByteConverter.LoadFromBytes<CoreSaveData>(_cloudData, UseSucessfullConvertedSavegameData);
} else {
//this will "fail", causing the use of the callback with the param "null"
SaveGameToByteConverter.LoadFromBytes<CoreSaveData>(null, UseSucessfullConvertedSavegameData);
}
}
private void UseSucessfullConvertedSavegameData(CoreSaveData _convertedSaveGame) {
//Has a Loaded & normal SaveGame in his cloud
if (_convertedSaveGame != null) {
//Loaded Save matches verify-conditions
if (CheckLoadedSaveIsVerified(_convertedSaveGame)) {
OverrideGameSaveDatawithLoaded(_convertedSaveGame);
ReloadCurrentScene();
return;
} else { //This happens if the cloud-save doesn't pass my verification-process
ErrorPopupWithCloseButton("cloud_loadedSave", "Couldn't find a compatible Savegame!");
return;
}
} else { //User uses Cloud-save for the frist Time or has an unusable savegame and gets a "new" (lost his old data)
TrySaveGameToCloud((bool _saved) => {
SaveAllGameFilesLocally();
});
}
}
I shrunk the code by removing most of my “if error happens, do XY”, since there are many and they would extend the reprex. If necessary I can provide a more detailed (but more complicated) code.
current conclusion
I can't find any issue on my side, that wouldn't have been fixed with a "restart of the game" or woudln't been covered by an error-popup for the user. It's like they are queued because of the amount of users and need to wait way too long for a response. Some users told us they had to wait & tried "x hours" (it's variable from 2h to 36h) and then they passed to play with their progress (so it worked). But some players mentioned they couldn't play again on the next day (same problem). Like their "access-token" only holds for a day?
Edit-History:
(1) updated the first dash-board-picture to match the ongoing situation
(1) added "more informations about the cloud-situation"
(1) can't find a more detailed error-log
(2) removed most pictures as displayables (kept the links)
(2) added "more informations about the Error-Trace in the cloud-API"
(2) added "more informations about the Core-Code" and a Reprex
(2) added "current conclusion"
The below code is used to execute a long running calculation on a background thread:
enum CalculationInterface {
private static var latestKey: AnyObject? // Used to cancel previous calculations when a new one is initiated.
static func output(from input: Input, return: #escaping (Output?) -> ()) {
self.latestKey = EmptyObject()
let key = self.latestKey! // Made to enable capturing `self.latestKey's` value.
DispatchQueue.global().async {
do {
let output = try calculateOutput(from: input, shouldContinue: { key === self.latestKey }) // Function cancels by throwing an error.
DispatchQueue.main.async { if (key === self.latestKey) { `return`(output) } }
} catch {}
}
}
}
This function is called from the main thread like so:
/// Initiates calculation of the output and sets it to the result when finished.
private func recalculateOutput() {
self.output = .calculating // Triggers calculation in-progress animation for user.
CalculationInterface.output(from: input) { self.output = $0 } // Ends animation once set and displays calculated output to user.
}
I'm wondering if it's possible for the closure that's pushed to DispatchQueue.main to execute while the main thread is running my code. Or in other words execute after self.output = .calculating but before self.latestKey is re-set to the new object. If it could, then the stale calculation output could be displayed to the user.
I'm wondering if it's possible for the closure that's pushed to DispatchQueue.main to execute while the main thread is running my code
No, it isn't possible. The main queue is a serial queue. If code is running on the main queue, no "other" main queue code can run. Your DispatchQueue.main.async effectively means: "Wait until all code running on the main queue comes naturally to an end, and then run this on the main queue."
On the other hand, DispatchQueue.global() is not a serial queue. Thus it is theoretically possible for two calls to calculateOutput to overlap. That isn't something you want to have happen; you want to be sure that any executing instance of calculateOutput finishes (and we proceed to grapple with the latestKey) before another one can start. In other words, you want to ensure that the sequence
set latestKey on the main thread
perform calculateOutput in the background
look at latestKey on the main thread
happens coherently. The way to ensure that is to set aside a DispatchQueue that you create with DispatchQueue(label:), that you will always use for running calculateOutput. That queue will be a serial queue by default.
Let's say 2 different callback of an API request have to execute this same piece of code :
if flag == false {
flag = true // preventing the whole thing to be called multiple times
// Do something
// reset flag to false after 10 sec
}
Sometimes it happens that both threads were so simultaneous, that they both reach "// Do something" instructions.
What is the proper swifty way to resolve this case ?