Lua Tween Part Info - if-statement

I am making a tween that uses data given from a Humanoid.Seated event, and I wanted to make the camera go to the end point when sat down, however, move back after they sat up. I have a feeling that the problem is with the part info, however I could be wrong.
This is the code:
The Sender/Event Handler:
local camPart = script.Parent
local camEvent = game.ReplicatedStorage.CamEvent
local blueSeat = script.Parent.Parent.BlueSeat.Seat --the correct seat person should be in
local bluePlayerName = script.Parent.Parent.Buttons.BlueEnter.PlayerName --the supposed name of person
bluePlayerName:GetPropertyChangedSignal("Value"):Connect(function ()
if (bluePlayerName ~= "") then
local char = game.Workspace:FindFirstChild(bluePlayerName.Value, true)
local player = game.Players:GetPlayerFromCharacter(char)
char.Humanoid.Seated:Connect(function (isSeated, seat)
if (seat.Name == blueSeat.Name) then
camEvent:FireClient(player, camPart, isSeated) --go to tween handler
end
end)
end
end)
The Receiver/Tween Handler:
local TweenService = game:GetService("TweenService")
local cam = game.Workspace.Camera
local partData
local tween
local length = 2
local tweenData = TweenInfo.new(
length,
Enum.EasingStyle.Sine,
Enum.EasingDirection.Out,
0,
true,
0
)
script.Parent.OnClientEvent:Connect(function (camPart, isSeated) --receiver
partData = {
CFrame = camPart.CFrame
}
tween = TweenService:Create(cam, tweenData, partData)
if (isSeated == true) then
cam.CameraType = Enum.CameraType.Scriptable --remove control
tween:Play()
wait(length / 2)
tween:Pause() --stop at end point
elseif (isSeated == false) then
tween:Play() --go back/finish
wait(length / 2)
cam.CameraType = Enum.CameraType.Custom --give control back
end
end)

The fact that the RemoteEvent isn't firing at all should be an clue that the connection to the Humanoid.Seated event isn't being reached in the server Script. It's unclear from your code sample what would trigger the code in the first place, but it looks like you're just looking for when a player's character loads into the workspace.
I would recommend using the Player.CharacterAdded or Player.CharacterAppearanceLoaded events as ways of getting access to the player's Character and humanoid. You can still use your UI code as a trigger for whether to tween or not, but it might be easier.
-- Server Script
local camPart = script.Parent
local camEvent = game.ReplicatedStorage.CamEvent
local thing = script.Parent.Parent
local blueSeat = thing.BlueSeat.Seat --the correct seat person should be in
local bluePlayerName = thing.Buttons.BlueEnter.PlayerName --the supposed name of person
-- listen for when a player sits in a seat
game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
character.Humanoid.Seated:Connect(function(isSeated, seat)
print("Player is seated?", isSeated)
if not isSeated then
-- tell the client to zoom out
camEvent:FireClient(player, camPart, isSeated)
else
-- decide whether to tween the camera
local isApprovedSeat = seat.Name == blueSeat.Name
local isNameSet = bluePlayerName.Value ~= ""
local shouldTweenCamera = isApprovedSeat and isNameSet
if shouldTweenCamera then
camEvent:FireClient(player, camPart, isSeated)
else
local message = table.concat({
"Camera not tweening because: ",
"Player has claimed this seat? " .. tostring(hasClaimedSeat),
"This is the approved seat? " .. tostring(isApprovedSeat)
}, "\n")
warn(messsage)
end
end
end)
end)
end)
Also, it looks like the LocalScript that is listening for this RemoteEvent is located in ReplicatedStorage. Check the documentation on LocalScripts, they only fire in a handful of locations, and ReplicatedStorage unfortunately isn't one of them. Try moving the LocalScript into StarterCharacterScripts and update the path to the RemoteEvent.
local camEvent = game.ReplicatedStorage.CamEvent
camEvent.OnClientEvent:Connect(function (camPart, isSeated) --receiver

Related

Google Storageclient.ListObjects causes thread cancel when deployed to server

I have some code that fetches files from Google Cloud Storage. The code works fine when run on my local development machine but when deployed to our production server it always "stops" whenever the parameter "objectsInBucket" (in the code below) is used.
In the example below the last code that actually executes correctly when deployed to the server is the line "LogHelper.LogToConsole("-6").
If I "uncomment" the foreach loop the last output to console is "- 4". Also, if I for example make a variable like "var count = objectsInBucket.Count();" and put it immediately after "objectsInBucket = storageClient.Listobjects(_gcsBucketName);" then the last output will be "- 1".
But like I said, this problem only occurs when deployed to the server. So what can the cause of this be?
Google.Api.Gax.PagedEnumerable<Google.Apis.Storage.v1.Data.Objects, Google.Apis.Storage.v1.Data.Object> objectsInBucket = null;
LogHelper.LogToConsole($" - 1");
objectsInBucket = storageClient.ListObjects(_gcsBucketName);
LogHelper.LogToConsole($" - 2");
//var count = objectsInBucket.Count(); // this causes last output to be "- 2"
var dirPath = Path.Combine(_gcsAttachemntPath, attachmentId);
LogHelper.LogToConsole($" - 3");
if (objectsInBucket != null)
{
LogHelper.LogToConsole($" - 4");
//LogHelper.LogToConsole($" - {objectsInBucket.Count()} attachments exists on bucket:");
//foreach (var obj in objectsInBucket)
//{
// LogHelper.LogToConsole($" - - {obj.Name}");
//}
LogHelper.LogToConsole($" - 5");
var directoryInfo = new DirectoryInfo(dirPath);
if (directoryInfo.Exists)
{
LogHelper.LogToConsole($" - Deleting directory: {dirPath}");
directoryInfo.Delete(true);
}
directoryInfo.Create();
LogHelper.LogToConsole($" - Directory created: {dirPath}");
}
LogHelper.LogToConsole($" - 6");
var attachmentFiles = objectsInBucket.Where(x => x.Name.Contains(attachmentId));
From the code you shared It seems you want to achieve this: If an object exists in the folder you want to delete the object and create a subfolder in the same folder.If it does not exist create a subfolder directly in the folder..I am not much experienced in C# the below code may help you i think.
StorageClient storageClient = StorageClient.Create(projectId);
string bucketName = "bucketName";
string folderName = "folderToCreate";
string objectName = "ObjectToCheckToExist";
bool objectExists = storageClient.GetObject(bucketName, $"{folderName}/{objectName}") != null;
if (objectExists){
storageClient.DeleteObject(bucketName, $"{folderName}/{objectName}");
storageClient.DeleteFolder(bucketName, folderName);
}
else {
storageClient.CreateFolder(bucketName, folderName);
}
Also have a look at official document as well.
answers were much appreciated.
It turns out that for some reason this call was blocked in the firewall on the server.
We were made available a proxy to use when doing these calls.
Then, when using the proxy, everything worked fine.

Calling get_position on KinematicBody2D causes a get_global_transform error

Summary
I'm trying write a unit test using Gut for my player in gdscript but calling get_position() on the player (a KinematicBody2D) is causing the following error:
ERROR: get_global_transform: Condition "!is_inside_tree()" is true. Returned: get_transform()
At: scene/2d/canvas_item.cpp:467.
ERROR: body_test_motion: Condition "!body->get_space()" is true. Returned: false
At: servers/physics_2d/physics_2d_server_sw.cpp:1046.
ERROR: get_global_transform: Condition "!is_inside_tree()" is true. Returned: get_transform()
At: scene/2d/canvas_item.cpp:467.
ERROR: body_test_ray_separation: Condition "!body->get_space()" is true. Returned: false
At: servers/physics_2d/physics_2d_server_sw.cpp:1058.
Expectation
I was expecting that after _physics_process() I would be able to get the updated position of my player but it returns Vector2(0, 0).
Resources
This is my first time using GDScript so I have been using a mixture of the following resources in an attempt to write this first test:
8-way movement
TDD and PONG Episode 1
GUT Command-line
Stubbing Input Class
Failed solutions
I think I may need to make the player a child of something else but I'm unsure how to do this within my test.
I tried searching the Gut issues on how to use add_child() within a test but I couldn't find an answer.
I also tried making the player a child of an Area2D but that didn't seem to work either:
var player := Player.new(input)
var area := Area2D.new()
area.add_child(player)
Code
This is the code that is causing the error when calling gut from the command line:
test/unit/actors/test_player.gd
extends "res://addons/gut/test.gd"
func test_can_create_player() -> void:
var input = MockInput.new()
var player := Player.new(input)
assert_not_null(player)
func test_can_move_player_up() -> void:
var input = MockInput.new()
input.press("ui_up")
var player := Player.new(input)
simulate(player, 1, .1)
assert_eq(player.get_position(), Vector2(200, 0))
test/mock_input.gd
class_name MockInput
var _pressed: Dictionary = {}
func press(key: String) -> void:
_pressed[key] = true
func release(key: String) -> void:
_pressed[key] = false
func is_action_pressed(key: String) -> bool:
if _pressed.has(key):
return _pressed.get(key)
return false
entities/actors/player.gd
extends KinematicBody2D
class_name Player
export var speed: int = 200
var _input: Object = Input
var _velocity: Vector2 = Vector2()
func _init(input: Object = Input):
_input = input
func _physics_process(_delta: float) -> void:
_velocity = Vector2()
if _input.is_action_pressed("ui_right"):
_velocity.x += 1
if _input.is_action_pressed("ui_left"):
_velocity.x -= 1
if _input.is_action_pressed("ui_down"):
_velocity.y += 1
if _input.is_action_pressed("ui_up"):
_velocity.y -= 1
_velocity = _velocity.normalized() * speed
_velocity = move_and_slide(_velocity)
The error is telling you !is_inside_tree(). The problem is not -only- that the node does not have a parent. The problem is that it is not inside a SceneTree.
You can create your own instance of SceneTree. You can even extend it. For example, this would work:
var node := KinematicBody2D.new()
var tree := SceneTree.new()
tree.get_root().add_child(node)
yield(tree, "idle_frame")
print(node.get_global_transform())
Now, about Gut… Your tests will be running inside a SceneTree. Thus, you can add the nodes you want to test as children. Just remember to do proper teardown (remove the nodes). Because Gut will not do it for you, and if children nodes linger from one test to another, then they aren't units anymore.
Addendum: You can use add_child_autofree to add a child, and also queue it for freeing right after the test ends.
The rest of the answer is me going over how Gut runs tests to confirm they run inside a SceneTree.
The file gut_cmdln.gd is actually an extended SceneTree. It will load gut.gd (here) and add it as a node to itself (here).
In turn, gut.gd is in charge of running the tests, which is handled by _test_the_scripts. What I want you to look is this:
var test_script = the_script.get_new()
var script_result = null
_setup_script(test_script)
There the_script is a TestScript object. The get_new call will return an instance. And _setup_script…
func _setup_script(test_script):
test_script.gut = self
test_script.set_logger(_lgr)
add_child(test_script)
_test_script_objects.append(test_script)
Will add it as child (of gud.gd).
Afterwards _test_the_scripts will go into a loop (here) and call _run_test or _run_parameterized_test (which calls _run_test) to actually run the test. And _run_test will use call on the instance to run the test method (with extra steps).
Huzza! Your tests will be running in a custom SceneTree.
I found something that worked for my purposes (I'm a little bit annoyed that I missed this the first time).
As I suspected, the player needs to be a child of another Node.
In the test/unit/actors/test_player.gd after the player variable has been defined it can be added as a child of the test itself using:
self.add_child_autofree(player)
With the complete unit test as the following:
func test_can_move_player_up() -> void:
var input = MockInput.new()
input.press("ui_up")
var player := Player.new(input)
self.add_child_autofree(player)
simulate(player, 1, 0)
assert_eq(player.get_position().round(), Vector2(0, -30))

how to prevent another where chain from quering db again

I have an object called work_shift_stops created with .where and after modified to limit start and end_time, with code below:
work_shift_stops = Stoppage20.where(["machine20_id = :machine20_id AND (end_time >= :start AND start <= :end_time)",
{ machine20_id: params[:shift_result][:machine20_id],
end_time: work_shift.end,
start: work_shift.first}])
work_shift_stops.each do |ws|
ws.start = work_shift.first if ws.start < work_shift.first
ws.end_time = work_shift.end if ws.end_time > work_shift.end
end
Further in my code I am using another where chain on the object:
load_time = open_time - work_shift_stops.where(stop20_id: Stop20.where(stop_group20_id: 3).pluck(:id)).sum(:duration)
This gives unpleasant result as rails is making another db query, which retrieves work_shift_stops with unmodified start and end_time limits:
SELECT SUM("stoppage20s"."duration") AS sum_id FROM "stoppage20s" WHERE (machine20_id = '1' AND (end_time >= '2013-03-02 05:00:00.000000' AND start <= '2013-03-02 17:00:00.000000')) AND "stoppage20s"."stop20_id" IN (12, 17)
Question is how to prevent rails from making another db query and use object with modified attributes?
What I actually did was dropping .sum(:duration) function and iterating on active record collection work_shift_stopswith modified start and end_time:
work_shift_stops.each do |wsd|
planned_stops_time += wsd.duration if Stop20.where(stop_group20_id: 3).pluck(:id).include? wsd.stop20_id
tech_stops_time += wsd.duration if Stop20.where(stop_group20_id: 1).pluck(:id).include? wsd.stop20_id
org_stops_time += wsd.duration if Stop20.where(stop_group20_id: 2).pluck(:id).include? wsd.stop20_id
end

Lua: pass context into loadstring?

I'm trying to pass context into a dynamic expression that I evaluate every iteration of a for loop. I understand that the load string only evaluates within a global context meaning local variables are inaccessible. In my case I work around this limitation by converting a local into a global for the purpose of the string evaluation. Here's what I have:
require 'cosmo'
model = { { player = "Cliff", age = 35, gender = "male" }, { player = "Ally", age = 36, gender = "female" }, { player = "Jasmine", age = 13, gender = "female" }, { player = "Lauren", age = 6.5, gender = "female" } }
values = { eval = function(args)
output = ''
condition = assert(loadstring('return ' .. args.condition))
for _, it in ipairs(model) do
each = it
if condition() then
output = output .. each.player .. ' age: ' .. each.age .. ' ' .. '\n'
end
end
return output
end }
template = "$eval{ condition = 'each.age < 30' }"
result = cosmo.fill(template, values)
print (result)
My ultimate goal (other than mastering Lua) is to build out an XSLT like tempting engine where I could do something like:
apply_templates{ match = each.age > 30}[[<parent-player>$each.player</parent-player>]]
apply_templates{ match = each.age > 30}[[<child-player>$each.player</child-player>]]
...And generate different outputs. Currently I'm stuck on my above hawkish means of sharing a local context thru a global. Does anyone here have better insight on how I'd go about doing what I'm attempting to do?
It's worth noting that setfenv was removed from Lua 5.2 and loadstring is deprecated. 5.2 is pretty new so you won't have to worry about it for a while, but it is possible to write a load routine that works for both versions:
local function load_code(code, environment)
if setfenv and loadstring then
local f = assert(loadstring(code))
setfenv(f,environment)
return f
else
return assert(load(code, nil,"t",environment))
end
end
local context = {}
context.string = string
context.table = table
-- etc. add libraries/functions that are safe for your application.
-- see: http://lua-users.org/wiki/SandBoxes
local condition = load_code("return " .. args.condition, context)
Version 5.2's load handles both the old loadstring behavior and sets the environment (context, in your example). Version 5.2 also changes the concept of environments, so loadstring may be the least of your worries. Still, it's something to consider to possibly save yourself some work down the road.
You can change the context of a function with setfenv(). This allows you to basically sandbox the loaded function into its own private environment. Something like the following should work:
local context = {}
local condition = assert(loadstring('return ' .. args.condition))
setfenv(condition, context)
for _, it in ipairs(model) do
context['each'] = it
if condition() then
-- ...
This will also prevent the condition value from being able to access any data you don't want it to, or more crucially, modifying any data you don't want it to. Note, however, that you'll need to expose any top-level bindings into the context table that you want condition to be able to access (e.g. if you want it to have access to the math package then you'll need to stick that into context). Alternatively, if you don't have any problem with condition having global access and you simply want to deal with not making your local a global, you can use a metatable on context to have it pass unknown indexes through to _G:
setmetatable(context, { __index = _G })

Blackberry - Is this a guaranteed approach for detecting a valid connection type?

I've created following two methods for reliably building a connection for making a data connection. So far I haven't had any issues testing this approach with users.
I'd love to get some community feedback about this approach and letting me know if anything seems in buildConnectionString(). Please see code below:
private static String buildConnectionString()
{
//The Device is a simultaor --> TCP
if (DeviceInfo.isSimulator())
return ";deviceside=true;ConnectionTimeout=20000";
String st = "";
//A carrier is providing us with the data service
if ((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_CARRIER) == CoverageInfo.COVERAGE_CARRIER)
{
// blackberry internet service
ServiceRecord rec = getBIBSRecord();//Apply for BIS access to get info about BIS recordset
if (rec != null)//couldn't find the right record
st = "[THIS CONNECTION STRING IS REMOVED, PLEASE APPLY FOR BIS ACCESS TO GET THIS STRING]";
else if(GetWap2().length() > 0)
st = GetWap2();
else
st = ";deviceside=true";// let the phone try to do the work
}
else if ((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_MDS) == CoverageInfo.COVERAGE_MDS)
st = ";deviceside=false";// use the clients blackberry enterprise server
else
st = ";deviceside=true";// let the phone do the work if it can
return st + ";ConnectionTimeout=45000";
}
public static String GetWap2() {
String wap2Postfix = null;
final ServiceBook sb = ServiceBook.getSB();
final ServiceRecord[] records = sb.findRecordsByCid("WPTCP");
for (int i = 0; i < records.length; i++) {
// Search through all service records to find the valid non Wi-Fi
// WAP 2.0 Gateway Service Record.
if (records[i].isValid() && !records[i].isDisabled()
&& records[i].getUid() != null
&& records[i].getUid().length() != 0
&& records[i].getUid().toLowerCase().indexOf("wifi") == -1
&& records[i].getUid().toLowerCase().indexOf("mms") == -1) {
wap2Postfix = ";ConnectionUID=" + records[i].getUid();
break;
}//endif
}//end for
return wap2Postfix;
}// end wap postfix
Possible questions to consider:
If a BIS string exists (recordset found), will it always work (aside from being blocked by a corporate network)?
If a WAP2 string exists (recordset found), will it always work (aside from being blocked by a corporate network)?
Should I check for MDS support first as opposed to carrier support?
Beyond extreme cases where carriers block a connection, will the above approach work?
Let me me know!
Check this code:
http://developerlife.com/tutorials/?p=884