I am connecting to a remote web server to get mouse movements stored in a database. The processing program I've written to animate these movements has been INCREDIBLY choppy since putting the code on the server. I realize this is because rather than running locally it's got to fetch the information, but is it possible to speed things up a bit? Here's the code I'm using
String get_users = "http://example.com/get_users.php";
String get_data = "http://example.com/get_data.php?user=";
ArrayList arrows;
PImage mouse;
int[] user_ids;
int num_users;
void setup() {
size(1024, 768);
frameRate(24);
smooth();
noStroke();
mouse = loadImage("arrow-clear.png");
arrows = new ArrayList();
getUsers();
for (int i = 0; i < num_users; i++){
arrows.add(new Arrow(user_ids[i], i*400, 2*i*100));
}
}
void getUsers(){
user_ids = int(loadStrings(get_users));
num_users = user_ids.length;
println(num_users);
}
void draw() {
background(0);
if (frameCount % 600 == 0){
getUsers();
for (int i = 0; i < num_users; i++){
arrows.add(new Arrow(user_ids[i], i*400, 2*i*100));
}
}
for (int i = arrows.size()-1; i >= 0; i--) {
Arrow arrow = (Arrow) arrows.get(i);
arrow.move();
if (arrow.finished()) {
arrows.remove(i);
}
}
}
class Arrow {
String[] all_moves, move_pairs, new_moves;
int[] moves;
float x;
float y;
int id;
int i = 0;
Boolean is_done = false;
Arrow(int tempID, float tempX, float tempY) {
all_moves = loadStrings(get_data + tempID);
id = tempID;
x = tempX;
y = tempY;
if (all_moves.length > 0){
move_pairs = shorten(split(all_moves[0], "|"));
}
}
void move() {
if (move_pairs != null){
if (i < move_pairs.length){
moves = int(split(move_pairs[i], ","));
image(mouse, moves[0], moves[1]);
++i;
} else {
all_moves = loadStrings(get_data + id);
if (all_moves.length > 0){
new_moves = shorten(split(all_moves[0], "|"));
for (int j = 0; j < new_moves.length; j++){
move_pairs = append(move_pairs, new_moves[j]);
}
println(move_pairs);
} else {
is_done = true;
}
}
} else {
is_done = true;
}
}
boolean finished() {
if (is_done) {
return true;
} else {
return false;
}
}
}
EDIT: To clarify: the Processing application doing all the animation is running locally. The X and Y points for the mouse is the only thing getting downloaded from the server.
You want to get all of the movement data (or large chunks of it) down to the client, and let the client do the work of animating everything.
I doubt it is a good idea to download the movement data on every single frame. If you don't need such detailed responsiveness, fetch a batch of movements from the server periodically and queue them for the draw method. Otherwise make sure the server sends only the data needed. I realized that you only use the first line of the data fetched from the server - all_moves[0]. If there is indeed only one line at all - fine.
You should consider using createInput(URL) and read from that stream, this way you wouldn't need to open a new input stream for every movement requested, but your server side code must be able to maintain the streams and write to them continuously.
Related
My first ever question on here as I'm completely stuck, so apologies if I leave out any key information - please let me know!
I am creating a PHP Battleships game and trying to use full OO. I'm really close, however, an array for one of my classes does not hold any updates I make to it.
First off, I dynamically
created a HTML table with an onclick event - which passes the coordinates to a JS function.
I then make an AJAX call in jQuery:
function shotFired(row, column) {
var coords = {
x: row,
y: column
};
$.post("data/game_controller.php", {
jsonCoords: JSON.stringify(coords)
}, function(results) {
console.log(results)
console.log(results[4])
var playerShotResult = results[0];
var computerShotX = results[1] + 1;
var computerShotY = results[2] + 1;
var computerShotResult = results[3];
var positionsClicked = document.getElementById("computer_" + row + "," + column)
switch (playerShotResult) {
case "MISS":
positionsClicked.classList.add("miss");
break;
case "HIT":
positionsClicked.classList.add("hit");
break;
case "Already Hit":
document.getElementById("outputMessage").innerHTML = result
break;
default:
console.log("Player shot defaulted");
}
}, "json")
I then use game_controller.php to handle the request and call shotFired:
<?php
session_start();
require("../classes/Game.class.php");
if (isset($_POST['jsonCoords'])) {
if (isset($_SESSION['newGame'])) {
$game = unserialize($_SESSION['newGame']);
$coords = json_decode($_POST['jsonCoords']);
$results = $game->shotFired($coords->x, $coords->y);
echo json_encode($results);
}
}
shotFired from the Game.php Class file, gets an instance of the Fleet class called computer, and runs the checkPosition function:
public function shotFired($x, $y)
{
$computer = $this->getComputer();
$playerHit = $computer->checkPosition(($x - 1), ($y - 1));
$computerGrid = $computer->getBattleshipsGrid();
$computerHit = $this->simulateComputerShot();
return [$playerHit, $computerHit[0], $computerHit[1], $computerHit[2], $computerGrid];
}
checksPosition checks the State of the Position instance in the BattleshipGrid array, and then attempts to update the array with a H or M - using a standard setter method:
public function checkPosition($x, $y): string
{
$positionObj = $this->battleshipsGrid["(" . $x . "," . $y . ")"];
$positionState = $positionObj->getState();
if ($positionState == "#") {
$positionObj->setState("M");
return "MISS";
} elseif ($positionState == "M" || $positionState == "H") {
return "Already Fired";
} else {
$positionObj->setState("H");
return "HIT";
}
}
For reference, I set the Battleships board in the constructor for Fleet.php:
// Populate associative array with instances of position
for ($y = 0; $y < $gridSize; $y++) {
for ($x = 0; $x < $gridSize; $x++) {
$coordinates = "(" . $x . "," . $y . ")";
$this->battleshipsGrid[$coordinates] = new Position($x, $y);
}
}
It works directly after it has been set - however, on the next onclick event, the H or M value is reset to it's previous value?
Seen here in console output
After a couple of hours, the closest I've come to is passing byRef in the setState function (didn't make a difference).
I've seen some notes on array_map, but I'm not sure this is what I'm looking for?
For ref, this is how I output the battleshipGrid to the console:
public function getBattleshipsGrid()
{
$readableGrid = "";
$grid = $this->battleshipsGrid;
foreach ($grid as $coordsID => $positionObj) {
$readableGrid .= "\n" . $coordsID . ": " . $positionObj->getState();
}
return $readableGrid;
}
Apologies for the long post, but I didn't want to leave anything out. Any and all help would be extremely appreciated!
Many thanks
It looks like you're not saving the state of the coordinates of the hits. If you are using the eloquent model, and setState is changing the attribute's value, make sure that you call $positionObj->save() as php does not save state on each ajax request. You will need to use a database or some sort of storage to have the server 'remember' that you clicked a specific location.
Our distributed database have php client which is developed on php extension.
We store our database object in persistant_list.
Problem:
From the log we find, for the same process, sometimes it can't find the database object from persistent_list, have to init the db object in persistant_list, but later(probably 1s)it can't find the same key-value again. It seems the value in persistent list is destroyed. Based on my poor knowledge about php, the values in persistent_list only destroyed by zend_hash_del or web server down. Source code:
if (zend_hash_find(&EG(persistent_list), hash_key, hash_key_len+1, (void **) &le) == FAILURE) {
tc = tair_init();
last_rst = tair_startup(tc,uri);
if(last_rst != TAIR_RETURN_SUCCESS){
return -1;
}
zend_rsrc_list_entry new_le;
new_le.type = le_tair;
new_le.ptr = tc;
/* register new persistent connection */
if (zend_hash_update(&EG(persistent_list), hash_key, hash_key_len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
tair_deinit(tc);
tc = NULL;
} else {
rsrc_id = zend_list_insert(tc,le_tair);
}
}else if (le->type != le_tair || le->ptr == NULL) {
zend_hash_del(&EG(persistent_list), hash_key, hash_key_len+1);
tc = tair_init();
last_rst = tair_startup(tc,uri);
if(last_rst != TAIR_RETURN_SUCCESS){
return -1;
}
zend_rsrc_list_entry new_le;
new_le.type = le_tair;
new_le.ptr = tc;
if (zend_hash_update(&EG(persistent_list), hash_key, hash_key_len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
tair_deinit(tc);
tc = NULL;
} else {
rsrc_id = zend_list_insert(tc,le_tair);
}
}else {
tc = (tair_handler)le->ptr;
rsrc_id = zend_list_insert(tc,le_tair);
}
PHP_MINIT_FUNCTION(tair)
{
REGISTER_INI_ENTRIES();
tair_set_loglevel(tair_globals.log_level);
le_tair = zend_register_list_destructors_ex(NULL,tair_dtor,"Tair session", module_number);
return SUCCESS;
}
Can anyone tell me what's wrong with my php zend engine? Btw the client side use Nginx+fpm.
I have webapp that is logging application and I need backup/restore/import/export feature there. I did this successfully with laravel but have some complications with Phalcon. I don't see native functions in phalcon that would split on chunks execution of large php scripts.
The thing is that logs will be backed up and restored as well as imported by users in ADIF format (adif.org) I have parser for that format which converts file to array of arrays then every record should search through another table, containing 2000 regular expressions, and find 3-10 matches there and connect imported records in one table to those in another table (model relation hasMany) That means that every imported record should have quite some processing time. laravel did it somehow with 3500 records imported, I dont know how it will handle more. The average import will contain 10000 records and each of them need to be verified with 2000 regular expression.
The main issue is how to split this huge processing mount into smaller chunks so I wouldnt get timeouts?
Here is the function that could flawlessly do the job with adding 3862 records in one table and as a result of processing of every record add 8119 records in another table:
public function restoreAction()
{
$this->view->disable();
$user = Users::findFirst($this->session->auth['id']);
if ($this->request->isPost()) {
if ($this->request->isAjax()) {
$frontCache = new CacheData(array(
"lifetime" => 21600
));
$cache = new CacheFile($frontCache, array(
"cacheDir" => "../plc/app/cache/"
));
$cacheKey = $this->request->getPost('fileName').'.cache';
$records = $cache->get($cacheKey);
if ($records === null) {
$rowsPerChunk = 50;
$adifSource = AdifHelper::parseFile(BASE_URL.'/uploads/'.$user->getUsername().'/'.$this->request->getPost('fileName'));
$records = array_chunk($adifSource, $rowsPerChunk);
$key = array_keys($records);
$size = count($key);
}
for ($i = 0; $i < $size; $i++) {
if (!isset($records[$i])) {
break;
}
set_time_limit(50);
for ($j=0; $j < $rowsPerChunk; $j++) {
$result = $records[$i][$j];
if (!isset($result)) {
break;
}
if(isset($result['call'])) {
$p = new PrefixHelper($result['call']);
}
$bandId = (isset($result['band']) && (strlen($result['band']) > 2)) ? Bands::findFirstByName($result['band'])->getId() : null;
$infos = (isset($p)) ? $p->prefixInfo() : null;
if (is_array($infos)) {
if (isset($result['qsl_sent']) && ($result['qsl_sent'] == 'q')) {
$qsl_rcvd = 'R';
} else if (isset($result['eqsl_qsl_sent']) && ($result['eqsl_qsl_sent'] == 'c')) {
$qsl_rcvd = 'y';
} else if (isset($result['qsl_rcvd'])) {
$qsl_rcvd = $result['qsl_rcvd'];
} else {
$qsl_rcvd ='i';
}
$logRow = new Logs();
$logRow->setCall($result['call']);
$logRow->setDatetime(date('Y-m-d H:i:s',strtotime($result['qso_date'].' '.$result['time_on'])));
$logRow->setFreq(isset($result['freq']) ? $result['freq'] : 0);
$logRow->setRst($result['rst_sent']);
$logRow->setQslnote(isset($result['qslmsg']) ? $result['qslmsg'] : '');
$logRow->setComment(isset($result['comment']) ? $result['comment'] : '');
$logRow->setQslRcvd($qsl_rcvd);
$logRow->setQslVia(isset($result['qsl_sent_via']) ? $result['qsl_sent_via'] : 'e');
$logRow->band_id = $bandId;
$logRow->user_id = $this->session->auth['id'];
$success = $logRow->save();
if ($success) {
foreach ($infos as $info) {
if (is_object($info)) {
$inf = new Infos();
$inf->setLat($info->lat);
$inf->setLon($info->lon);
$inf->setCq($info->cq);
$inf->setItu($info->itu);
if (isset($result['iota'])) {
$inf->setIota($result['iota']);
}
if (isset($result['pfx'])) {
$inf->setPfx($result['pfx']);
}
if (isset($result['gridsquare'])) {
$inf->setGrid($result['gridsquare']);
} else if (isset($result['grid'])) {
$inf->setGrid($result['grid']);
}
$inf->qso_id = $logRow->getId();
$inf->prefix_id = $info->id;
$infSuccess[] = $inf->save();
}
}
}
}
}
sleep(1);
}
}
}
}
I know, the script needs a lot of improvement but for now the task was just to make it work.
I think that the good practice for large processing task in php is console applications, that doesn't have restrictions in execution time and can be setup with more memory for execution.
As for phalcon, it has builtin mechanism for running and processing cli tasks - Command Line Applications (this link will always point to the documentation of a phalcon latest version)
I'm trying to convert the LZW decompressor from JSend which is in php to javascript, and I've gotten to a function I can't quite make sense of.
private static function decompressLZW($aCodes)
{
$sData = '';
$oDictionary = range("\x0000", "\xff");
foreach ($aCodes as $sKey => $iCode)
{
$sElement = $oDictionary[$iCode];
if (!isset($sElement))
$sElement = $sWord . $sWord[0];
$sData .= $sElement;
if ($sKey)
$oDictionary[] = $sWord . $sElement[0];
$sWord = $sElement;
}
return $sData;
}
This is what I have in javascript so far, but I when I run this in javascript, it complains that sWord isn't defined and looking at the php function, I don't see how this doesn't produce an error?
Here's what I have in javscript so far:
function decompressLZW(aCodes) {
var sData = '';
var oDictionary = [];
for (var i = 0; i < 256; i++) {
oDictionary[String.fromCharCode(i)] = i;
}
for(var i=0, iLn = aCodes.length; i < iLn; i++) {
var sElement = oDictionary[aCodes[i]];
if(!sElement) {
sElement = sWord + sWord[0];
}
//some magic needs to happen here
}
return sData;
}
Well its kind of bad IMO but.... $sWord is essentially $sElement which is defined near the end of the iteration. They are counting on the first two if statements be true only after the at least a single run of the loop in which case $sWord would be the same as the previous iteration's $sElement.
Im not sure what the significance of that assumption is but if it were me i would still test for the existence of $sWord and throw an exception if that happened (even if it should theoretically never happen)...
So you need to figure out why sElement = oDictionary[aCodes[i]]; isnt evaluating to something truthy. It may be as simple as testing angainst undefined (which is more like doing isset()) instead of doing loose falsy check.
if(sElement === undefined) {
sElement = sWord + sWord[0];
}
I am looking to display something like:
Hello, you've reached this site by looking for [google keyword(s)]
I'm pretty sure I've seen this done before but I am having troubles figuring out how to grab the keywords that were used to lead a user to my site. Anyone know the answer?
You need to get the referring URL and then strip out everything for the "q" query string. This will give you the query that was used to get you to your page.
Using the referrer (http://www.netmechanic.com/news/vol4/javascript_no14.htm) you can find where the user comes from. Then it's just a matter of parsing it correctly.
I saw this script :
function getkeywords() {
var x = document.referrer;
var lastparturl = 0;
if (x.search(/google/) != -1) {
lastparturl = x.indexOf("&btnG=Google+Search");
x = x.slice(38,lastparturl);
x = x.concat("via google");
}
else if (x.search(/yahoo/) != -1) {
lastparturl = x.indexOf("&ei=UTF-8&iscqry=&fr=sfp");
x = x.slice(63,lastparturl);
x = x.concat("via yahoo");
}
else if (x.search(/ask.com/) != -1) {
lastparturl = x.indexOf("&search=search&qsrc=0&o=0&l=dir");
x = x.slice(25,lastparturl);
x = x.concat("via ask");
}
else if (x.search(/dogpile/) != -1) {
lastparturl = x.indexOf("/1/417/TopNavigation/Relevance/iq=true/zoom=off/_iceUrlFlag=7?_IceUrl=true");
x = x.slice(46,lastparturl);
x = x.concat("via dogpile");
}
else if (x.search(/altavista/) != -1) {
lastparturl = x.indexOf("&kgs=1&kls=0");
x = x.slice(48,lastparturl);
x = x.concat("via altavista");
}
else {
x = "no keywords available";
}
x = x.replace(/+/, " ");
return x;
}
Here http://www.webmonkey.com/codelibrary/Get_Referrer_Keywords
I'm not sure if it works perfectly, but it worked OK when I reached their website through google.
I also saw that some scripts that you can download do that, for instance: http://webscripts.softpedia.com/script/Search-Engines/Keyword-Grabber-45299.html
Again, this will need to be tested.