Sunday, December 23, 2012

Battlefield 3 Disconnects

For months I'd been having issues with lag and stuttering in the PC version of Battlefield 3. Worse, though, were frequent, seemingly random disconnects.

I'd connect to a server, be able to play for 10 minutes or more, then my system would lock up hard, unresponsive even to Ctrl-Alt-Del for a few minutes until finally BF3 exited and the Battlelog site came back with anything from a disconnect message to one saying I'd been kicked from the server. 

Despite having the latest updates to BF3 itself, as well as for EA's bloated and unnecessary Origin software, PunkBuster, and my system's video drivers and Windows updates, the disconnects continued to occur, making it so that I seldom if ever got to the end of a round without being disconnected.

Finally I decided to take the plunge and configure my DSL router with port forwarding specific to BF3's needs, according to this page on EA's support site.


The site PortForward.com handily provides instructions specific to many router makes and models for the PC, XBox 360, and PS3 versions of Battlefield 3. One note, for the listed TCP ports specific to the PC version, I found that all but ports 80 (http) and 443 (https) were necessary to seemingly work around the disconnect issues I'd been having. You might need these ports forwarded if you plan to have your PC act as a BF3 server, but given that I don't it doesn't seem to make a difference.

Why the BF3 installer or the game itself doesn't specifically tell you which ports to forward in the beginning I don't know. Why EA and DICE rush out their games hurriedly without addressing their users' complaints, I don't know either. I'm happy to have found this works around my problem, and that the game is at least playable for more than 10 minutes or so at a time, but given their track record with previous games and their various issues, I'd like to see BF3 go open source someday and get in the hands of numerous software developers who would likely care more about the game and its users than EA.




Friday, December 21, 2012

Foscam FI9820W Review

I recently purchased a pair of Foscam FI9820W wireless IP cameras to augment my existing pair of FI8918W ones.




Featuring 720p video resolution, H.264 video compression, pan and tilt capability, SD card support, and IR cut to help filter out distortion in the camera's daytime mode, wireless IP cameras like these are very handy because they can be placed anywhere within the reach of your wireless network and a household power outlet, and transmit images and even live video wirelessly. 

In addition, if a burglar happens to break in and swipe or disable the cameras themselves, there's a fair chance that before this happens, the camera will have gotten a nice face shot of the perpetrator discovering the camera, and then send it via email or FTP if configured to do so, for you to later submit to the police.

This newest, more expensive camera in Foscam's lineup unfortunately suffers some significant shortcomings. Compared to the more mature FI8918W model, the web interface is still disappointingly ugly and Internet Explorer-centric, utilizing an ActiveX control to render live video in a browser and a few hoops need to be jumped through to get the interface functional in a more mainstream browser like Firefox or Chrome.

As if that were bad enough, a serious security issue arises with the FI9820W's lack of full WPA / WPA2 passphrase support. If your wireless network happens to be protected with one of these security protocols and uses anything other than an alphanumeric passphrase, you'll have no choice but to compromise your wireless security by making your password simpler to accommodate this camera.

Although the picture quality is outstanding in the camera's grayscale night vision mode with all its H.264 sharpness, the daytime mode leaves much to be desired. Even in a well-lit room the image appears blurry and washed out in spite of the included IR cut feature.

Night vision engaged, the image is relatively sharp and clear.



Another downside, whereas with the FI8918W you could set up its motion detection to optionally take a variable number of snapshots, the FI9820W allows no more than a single snapshot per activation of the motion alarm. Add to that the fact that the camera shares the similarly short AC adapter cable as its predecessor, there isn't a lot to make this camera in its current form worth the higher cost.
 
Daytime, even with IR cut the image is disappointingly grainy and washed out.


To summarize...
PROS:
  • High video resolution.
  • Sharp night vision.
  • SD card support.
CONS:
  • Nonstandard WPA / WPA2 passphrase support.
  • Grainy, washed-out daytime video.
  • Internet Explorer centered, 1990s-era web interface.
  • Short AC adapter cable.


I contacted Foscam's U.S. based technical support about the camera's disappointing features and anemic firmware, who responded to my inquiry on the FI9820W's shortcomings:
"Your suggestions will forward to our R&D team, we'll try to fain [sic] these features in the future software. Highly appreciated your feedbacks. Thanks a lot."

Let's hope they will!

Saturday, September 15, 2012

Reseed Identity Using Variable

In a sproc that involves creating a copy of a production SQL table for testing, I wanted to reseed the identity of the new table to 1 more than the max of the production key value. 

I figured at first I'd just use the appropriate syntax for DBCC and just use a variable already at hand containing the max production value and add 1 to it, like so:

 DECLARE @MaxID int

 -- Grab the max identity value from production.
 SELECT @MaxID = MAX(ID) FROM dbo.MyProductionTable

 DBCC CHECKIDENT (MyProductionTable_COPY, reseed, @MaxID + 1) 


SQL, however, would have nothing of it:
Incorrect syntax near '+'.

To work around this, I decided to try creating a dynamic SQL string to incorporate the variable arithmetic:

 DECLARE @MaxID int
 DECLARE @SQL nvarchar(100)

 -- Grab the max identity value from production.
 SELECT @MaxID = MAX(ID) FROM dbo.MyProductionTable

 SET @SQL = 'DBCC CHECKIDENT (MyProductionTable_COPY, reseed, ' 
 + CAST(@MaxID + 1 AS nvarchar(10)) 
 + ')'


Now I can create the table and set its starting identity value to 1 greater than in production using a variable despite DBCC's syntax dictating otherwise.





Friday, August 31, 2012

Enforced Dependencies and Schemabinding

In trying to rename a table I encountered the dreaded error about enforced dependencies:
Object 'myTable' cannot be renamed because the object participates in enforced dependencies.

I first used the following script to identify the objects dependent upon the table:
SELECT DISTINCT o.object_id, o.name, o.type_desc, m.definition
FROM sys.sql_dependencies d
JOIN sys.objects o ON o.object_id = d.object_id
JOIN sys.objects r ON r.object_id = d.referenced_major_id
JOIN sys.sql_modules m ON m.object_id = o.object_id
WHERE d.class = 1
AND r.name = 'myTable'

This yielded the names of three objects in my database which happen to use SCHEMABINDING in their definitions.

I didn't want to manually alter and recreate these objects, so instead I decided to create a script which will find the SQL code for each object, remove the WITH SCHEMABINDING syntax, drop the existing objects and then recreate them sans schema binding.

DECLARE
     @TheTable varchar(100),

     @Count int,
     @Max int,

     @object_id int,
     @name varchar(50),
     @type_desc varchar(50),
     @definition nvarchar(max),
 
     @DropSQL nvarchar(max),
     @CreateSQL nvarchar(max)

-- Remove schemabinding from objects tied to table.
DECLARE @Objects TABLE
(
     ID int IDENTITY (1, 1) PRIMARY KEY NOT NULL,
     object_id int,
     name varchar(50),
     type_desc varchar(50),
     definition nvarchar(max)
)

-- Set the table name here:
SET @TheTable = 'MyTable'

INSERT INTO @Objects (object_id, name, type_desc, definition)
SELECT DISTINCT o.object_id, o.name, o.type_desc, m.definition
FROM sys.sql_dependencies d
JOIN sys.objects o ON o.object_id = d.object_id
JOIN sys.objects r ON r.object_id = d.referenced_major_id
JOIN sys.sql_modules m ON m.object_id = o.object_id
WHERE d.class = 1
AND r.name = @TheTable

UPDATE @Objects
SET definition = 
     CASE
          WHEN definition LIKE '%SCHEMABINDING%' THEN REPLACE(definition, 'WITH SCHEMABINDING', '')
          ELSE definition
     END


SELECT @Count = 1, @Max = COUNT(ID) FROM @Objects

WHILE @Count <= @Max
BEGIN

     SELECT @object_id = object_id, @name = name, @type_desc = type_desc, @definition = definition
     FROM @Objects
     WHERE ID = @Count

     SET @DropSQL =   'DROP ' 
     +
     CASE @type_desc 
          WHEN 'VIEW' THEN 'VIEW'
          WHEN 'SQL_SCALAR_FUNCTION' THEN 'FUNCTION'
          WHEN 'SQL_TABLE_VALUED_FUNCTION' THEN 'FUNCTION'
          WHEN 'SQL_STORED_PROCEDURE' THEN 'PROCEDURE'
          WHEN 'SQL_TRIGGER' THEN 'TRIGGER'
     END
     +
     ' '
     + 
     @name

     PRINT @DropSQL
     EXEC sp_executeSQL @DropSQL

     SET @CreateSQL = @definition

     PRINT @CreateSQL
     EXEC sp_executeSQL @CreateSQL

     SET @Count = @Count + 1

END


Now I can incorporate this logic into a sproc and not have to worry about meddlesome constraints if I'm going to be renaming tables. The above script has been tested successfully under SQL 2008 and 2012, and will be able to automatically drop and recreate views, scalar and table valued functions, sprocs and triggers.