Return false

Un blog IT de plus le blog de Hubebert.

Live Wallpaper Android (update w/ video)

Mardi 14 janvier 2014 à 20:02

Hop, petite reprise d’activité du blog.

Sans parler de mes projets sur moyen ou long terme, voici ma petite réalisation de la semaine. Ça fait un moment que je cherchais un live wallpaper sympa pour Android sans rien trouver de folichon. J’ai donc relevé mes manches et je m’en suis fait un moi même.untitled

Dans le cadre d’un projet d’études j’ai eu a utiliser cocos2d-x. Un framework en C++ qui à l’avantage d’être présent sur tout un tas de plateformes (Win/Lin/Mac, Android/iOS/WP/Blackberry). Pour Android, il utilise le NDK pour faire tourner le code sur la plateforme. En détournant un peu la classe d’appel par défaut de Java (la MainActivity) on peut en faire en Wallpaper capable de lire les inputs du touchscreen et de l’acceleromètre. C’est mon premier contact avec de l’Android, et très franchement c’est pas ma tasse de thé. Utiliser Eclipse et bouffer des fichiers de config XML par tous les orifices, c’est pas l’éclate. Heureusement que j’avais quelques amis compétents sur le sujet pour me décoincer.

moving

Bref, avec un bout de code, trois rustines et 2-3 jours à faire des animations, je suis arrivé a quelquechose de présentable que mes amis m’ont convaincu de mettre sur le store. C’est fait pour Nexus 4 à l’origine, et testé uniquement sur Nexus 4 et 5. Du coup, tout retour d’éxperience de votre part sera bienvenu, avant que je me fasse massivement flamer sur le playstore a cause d’un bug ou d’un oubli de ma part.

YouTube Preview Image

TL;DR:

Và ici et dis moi si ça marche sur ton téléphone Android.

qr

GGJ 2014 - Cergy Pontoise édition

Lundi 6 janvier 2014 à 14:14

Pas de nouvelles depuis longtemps, mais je code toujours. Je compte reprendre ce blog tôt ou tard quand j’aurais plus de concret a présenter. Je fais une petite appartée pour vous parler de la Global Game Jam, dont Mr Helmut et Nemo ont déjà parlé ici. Comme d’habitude j’ai foiré mon inscription à Paris et je me retrouve sur liste d’attente. Sauf que cette année, j’ai reću un chouette mail de mon école m’annoncant qu’une orga était prévue à Cergy.

Comme je sais qu’il y a pas mal de talents sur Nofrag je fais tourner l’info : il reste des places !

Global Game Jam à Cergy du 24 au 26 janvier 2014
Venez participer au Global Gam Jam à Cergy en tant que développeur, graphiste, musicien ou simplement passionné  pour 48 heures d’échange et de convivialité autour de notre passion qu’est le jeux-vidéo.
Pour plus d’informations, rendez-vous sur http://ggj-cergy.fr/
Lieu où se déroulera le GGJ Cergy :

Visage du monde
10 place du nautilus, 95 000 Cergy
RER A Station Cergy le Haut

gpc

Présentation

Tout pareil que le_poulet j’ai participé à une compète de création de jeu vidéo en une semaine. La mienne, c’était la Game Prototype Challenge. Une compétition sans vainqueur (le défi est juste personnel) à laquelle j’ai participé par pure frustration d’avoir loupé la Global Game Jam à Paris. Les deux thèmes (parce que oui, il y en a deux obligatoires) de la 16° édition étaient :

FOUR COLOURS & ABSORBTION

L'écran artistique

L'écran artistique

Dev

Après une bonne nuit de réflexion je décide de faire un jeu de plateforme avec LÖVE, parce que j’ai vraiment pas d’idées. Un kirby simpliste en 3 couleurs Red Green et Blue. Je décide de ne pas utiliser la librairie physique Box2d,  je trouve ça un peu lourd pour de la collision de plateforme tout conne.

Red Green et Blue, ça fait que 3 couleurs, j’ajoute donc une 4° couleur: le joueur. En avalant des bouboules de couleurs, il modifie sa propre couleur, ce qui donne un côté un peu plus imprévu au graphisme, la dernière couleur évoluant sans cesse.

Je passe le weekend à  procrastiner parce que la réalisation du niveau ne me fait pas envie de tout. Au lieu de faire un level potable j’ajoute 3 mécaniques de jeu: plus on est vert, plus on court vite, plus on est bleu, plus on saute haut, et plus on est rouge, plus on est mort. J’ajoute à ça un paramètre pour que le perso rougisse -meure- à petit feu, et une capacité à “geler” la couleur des plateformes rencontrées pour faire joli.

Rectangle kid

Rectangle kid et ses boules

Résultat: un jeu qui pourrait être sympa s’il n’avait pas un niveau composé que de 4 platformes et une gestion des collisions scandaleuse.

Comme je suis un vilain tricheur j’ai débordé de la semaine du concours pour me construire un éditeur de niveaux et faire un niveau a peu près potable. Rien de bien folichon, mais c’est histoire de faire en sorte qu’une partie dure plus de 25 secondes.

Post-Mortem

Ce que je retiens de ces 25~30H (plus 10 hors compèt’) passées sur ce prototype.

Les bon côtés:

  • ça fonctionne…
  • meh…

Les points à revoir:

  • Finalement, utiliser box2d aurait surement rendu le jeu plus fun, en jouant avec une rotation des plateformes par exemple
  • Penser au level design plus tôt, et s’en préoccuper tout court
  • Prévoir l’intégration des sons dès le départ (je n’ai pas eu le temps d’en mettre du coup)

Download

Si vous voulez tester j’ai mis en ligne différentes versions.

La version portable pour windows (sans installation: unzip, click, play)

La version en .love (pour Linux/MacOS - nécessite LÖVE)

Le code source pour les curieux.

Seed - jeu de gestion végétal

Samedi 2 février 2013 à 11:52

Pas de nouvelle sur le développement depuis un bail, mais le projet est loin d’être mort.

Suite à la suggestion de MrHelmut,  en commentaire de mon article précédent, le jeu s’appellera Seed (et pas Weed, désolé).

Concept du menu

Concept du menu

Team up !

Avec mon appel à l’aide, deux nofragés m’ont proposé leur talents, on va donc avoir une belle production labellisée 100% wefrag. Et 100% pas FPS, cherchez l’erreur… Voici la liste des participants:

- Solentis au graphisme

- Khelben au son

- Moi même au code

C’est fait sur notre temps libre a chacun, donc ça avance à un rythme erratique, selon l’emploi du temps et la motivation, mais ça avance !

On a déjà une version présentable du menu principal et quelques mécaniques de jeu fonctionnelles, que je vais présenter succinctement ici.

Menu

On a commencé par intégrer le menu. Ça laisse libre cours à l’inspiration des artistes pendant que j’ai le temps de débuter le code gameplay. Pour rester dans l’ambiance, le menu prends la forme d’un arbre dont les branches sont les boutons. On en profite pour donner une idée du style graphique du jeu:

YouTube Preview Image

Gameplay

Je vais vous présenter ici le fonctionnement global de l’aspect ressources du jeu. Un arbre nécessite trois choses pour pousser, de l’eau de la terre et de la lumière. On aura donc trois ressources récupérables : eau, lumière et nutriment.

Chaque segment d’un arbre (racine, feuille, branche), consomme des ressources, et la branche est le seul élément à ne pas en récolter. Son rôle est uniquement utilitaire, et sert à atteindre des zones de récolte de lumière plus distantes du sol.

Les nutriments sont une ressource finie  à récolte constante. Plus on connecte de racines aux sources de nutriment, plus on en récolte rapidement. Une fois une zone épuisée, il faut creuser plus profond pour retrouver des nutriments. C’est la ressource qui pousse le joueur à s’étendre pour pouvoir se maintenir en vie.

L’eau est une ressource infinie, à collecte variable. On part du principe que le sol dispose d’un humidité générale, qui varie selon la saison. Elle aura l’occasion de changer à l’occasion de différents évènements, mais j’y reviendrais quand on parlera des évènements. On y ajoute des petites nappes phréatiques (ou waterspots) qui permettent de donner un

La lumière est une ressource infinie à collecte variable, on ne peut en collecter que le jour, et qu’avec les feuilles qui ne sont pas a l’ombre. Pour les espèces a feuilles non persistantes, l’hiver réduira drastiquement la collecte de lumière, de façon à encourager le joueur.

Pistes de réflexion

Pour l’instant il n’y a rien de définitif en terme de gameplay, même si le système de ressources commence à me sembler cohérent. Voici néanmoins quelques pistes de réflexion que je nourris en ce moment, libre a vous lecteur de commenter et de donner votre avis ou vos idées sur les sujet suivants.

  • Utiliser la branche comme stockage. Chaque branche peut contenir des ressources et augmente la quantité maximum qu’on peut conserver.
  • Les nappes phréatiques: les remplir après chaque pluie? Ne jamais les remplir?
  • Faire en sorte que plus une branche a de “filles” plus les feuilles consomment de resources. Ceci afin de forcer le joueur à se débarrasser des feuilles proches du tronc, et de donner à l’arbre un aspect plus réaliste.
  • Trouver un moyen simple et efficace de montrer comment évoluent les ressources. (Augmentation ou diminution) et d’identifier leur source (quelle racine rapporte le plus, et quelle feuille consomme le plus).

Comme toujours, remarques et retours sont appréciés, soit en commentaire, soit par email: hubebert_at_wefrag.com.

[TEST] Zero-K du RTS, du vrai

Vendredi 30 novembre 2012 à 21:43

zerok1

Présentation de Zero-K: il y a près de 3 ans j’avais parlé d’un mod excellent appellé Complete Annihilation. Il a bien mûrit et même changé de nom donc j’en refait une présentation, parce que je pense qu’il a un potentiel énorme, mais un manque crucial de joueurs. C’est toujours un RTS, c’est toujours open source, et toujours gratuit.

Bases

Zero-K , (pour 0 kelvin le zéro absolu en température) est donc la version aboutie de Complete Annihilation, lui même étant à l’origine un remake de Total Annihilation: LE mythique RTS de Chris Taylor. Ce qui caractérise ce genre de RTS, contrairement à ceux de Blizzard par exemple c’est l’échelle. Ici on utilise les ressources et les unités comme un flux. On ne compte pas le nombre d’unités a envoyer au combat, mais plutôt le nombre d’unité par minute. On commence la partie avec une unité spéciale: le commander. A la fois constructeur et combattant, il peut s’améliorer durant la partie.

Pour les ressources, il y a le métal et l’énergie.  L’énergie se récupère a l’aide de bâtiments (éolienne, panneaux solaires, centrales ect…). Le métal se récupère sur des spots précis et se recycle sur les carcasses. C’est ce dernier qui rends le map-control important: gagner quelques spots de métal en plus ou le contrôle sur un champ de bataille contenant d’importantes carcasses à recycler, peut donner un avantage économique décisif.

La spécificité de Zero-K c’est qu’il n’y a qu’une seule faction , et que toutes les usines d’unités sont accessibles dès le départ (pas de technologie à rechercher durant la partie). Cependant, il y a un système de progression entre les parties: chaque partie rapporte de l’XP qui permet au joueur d’acheter des technologies. Il s’agit essentiellement de nouveaux modules (armes, boucliers) pour le commander, ou de bâtiments spéciaux. Aussi curieux que ça puisse paraître, cela ne déséquilibre pas le jeu, ou très peu.

YouTube Preview Image

Multijoueur

Le parties vont du 1v1 au 10v10 et plus sans que cela ne pose de problème. Les parties avec beaucoup de joueurs sont intéressantes car elles obligent à déléguer énormément d’aspects a ses alliés et à se spécialiser. Les parties avec peu de joueurs (de 1v1 a 3v3) permettent de toucher un peu a tous les aspects.

Monde Persistant

Amélioration notable, une guerre persistante entre 4 groupes se déroule sur une carte de la galaxie. Dans ce mode, appelé Planet Wars, vous rejoignez une faction et essayer de remporter la victoire en conquérant le plus de planètes possibles. A chaque planète est associée une map, et une série d’améliorations. Lorsque la planète est attaquée, les joueurs se rencontre sur la map, qui est augmentée par les améliorations apportées par les possesseurs de la planète. Cela peut prendre la forme de bâtiments, d’unités de départ, ou de bonus durant la partie (+10% de récolte de métal par exemple).

Solo

Malgré la présence d’un éditeur de niveau simple et accessible a tous, il n’y a pas encore de campagne solo. Quelques missions scénarisées sortent du lot, mais rien qui ne puisse justifier le nom de jeu solo pour Zero-k.

YouTube Preview Image

TL;DR:

Tu veux un RTS super et pas cher? clic clic : http://zero-k.info/

Viens jouer avec nous sur le topic prévu à cet effet –> clic clic

projet de jeu - ça pousse

Dimanche 4 novembre 2012 à 2:58

Avant propos technique:

Petit point après une semaine d’utilisation du nouveau framework LÖVE.

C’est bien, c’est fluide, c’est cool. Comme je commence à ( essayer de ) m’entourer gens compétents, j’ai décidé de centraliser tout ce qui concerne le projet sur Bitbucket. Pour ceux qui ne connaissent pas, c’est un hébergeur de code source utilisant Git. Ça sert a pouvoir gérer les différentes version du projet avec un historique pour chaque fichier, et comme c’est décentralisé, chacun peu travailler de chez soi, et envoyer les données sur le serveur Bitbucket quand il a terminé son itération.

Pourquoi Bitbucket? Parce que j’aime bien l’interface, parce qu’on a un wiki en plus du stockage des fichiers et surtout pour la licence. Le gros concurrent de Bitbucket c’est GitHub. Les deux sites hébergent vos projets gratuitement si ceux-ci sont open-source (tout le code et le matériel de travail est public). Comme je n’ai pas encore pris de décision sur le sujet, je suis allé sur Bitbucket, qui permet d’avoir un code propriétaire hébergé gratuitement pour une équipe de 5 personnes ou moins. Pour l’instant c’est public, mais pouvoir changer d’avis sans sortir le chéquier, c’est toujours mieux.

Le semis:

Le jeu comportera des étapes de jeu différentes. Celle que j’ai entamée cette semaine est la première du cycle de reproduction, le semis. Lors de cette étape, le joueur ne contrôle qu’une graine/un fruit/un spore de son espèce. Il se pose quelque part et se plante, donnant naissance à une pousse, qui, dans les étapes de jeu suivantes deviendra arbre à part entière.

Pourquoi faire une étape de jeu entière la dessus? Parce qu’il y a la possibilité de laisser au joueur un choix intéressant: où se placer. En fonction des ressources, des problèmes de topographie possibles et autres, la partie peut être tout à fait différente. Et c’est aussi la première entorse à la réalité. Pour rappel, la règle principale du gamedesign est Aussi près de la réalité que possible, aussi loin que nécessaire. Pour le placement de la graine donc, on autorise le joueur à “bumper” sa graine. On lui donne une sorte de pichenette pour influencer sa trajectoire. Selon l’espèce choisie, on aura plus ou moins de bumps pour compenser d’autres avantages. En fonction du poids de la graine, le bump aura une influence plus ou moins importante.

YouTube Preview Image

Je précise que les ralentissements sont dus à la vidéo, et pas au moteur du jeu.

Éditeur de niveaux:

Pour gagner du temps sur des choses où il est bête d’en perdre, j’ai fait un éditeur de niveau. Il est encore moche et basique mais il fonctionne. Il est pour l’instant uniquement dédié à l’usage interne. Sortir un jeu avec un éditeur de niveaux c’est appréciable pour le joueur mais ça demande beaucoup de travail supplémentaire. On verra. En attendant ça m’a permis de jouer un peu avec le moteur physique du jeu.

Conclusion:

La suite:

  • finir le “semage” de la graine
  • attaquer la pousse de l’arbre.
  • Décider plus précisément de la gestion des ressources.
  • Intégrer le boulot des “game artists” (son, graphisme) dès qu’il y aura lieu.
  • Trouver un nom, même temporaire ! Si toi, lecteur de tu as une idée, n’hésite pas à me l’envoyer. (hube...@wefrag.com)

YouTube Preview Image

Décidément sur NF, on arrête pas de parler des jeux indés (et tant mieux). Vu qu’on a un forum sur lequel les gens ont de vrai débats (disons, moins pire qu’ailleurs) sur les jeux, avec des analyses (parfois) pertinentes ça donne des billes et des idées pour se lancer.

Projet de jeu de gestion végétal

Dimanche 28 octobre 2012 à 23:26

Bonjour à tous,

aujourd’hui une présentation d’un projet qui me tient à coeur. Comme beaucoup de nofragés, j’ai toujours voulu développer un jeu vidéo moi même. Maintenant que je suis en 4° année d’école d’IT je me suis permis une option Jeu Vidéo, et je me lance sur mon temps libre pour réaliser mon concept longuement mûri.

Avant-propos technique :

Afin de tester ma motivation et/ou la faisabilité technique, j’ai déjà travaillé environs 2 mois (depuis mi-Aout) sur la réalisation d’un prototype. (voir vidéos). Pour ce prototype j’ai utilisé le framework pygame qui permet de tout faire en Python. Il à l’avantage d’avoir d’excellentes performances pour la 2D et de faire gagner un temps monstre en code grâce au Python. Cependant, pendant la réalisation du prototype j’ai rencontrés quelques défauts qui m’ont poussé à passer à autre chose :

  • Pas d’antialiasing
  • Pas de Synchro verticale (!)
  • Gestion abominable du scroll
  • Packaging en .exe laborieux

J’ai donc donné sa chance au plus récent framework LÖVE. Tout comme pygame, il utilise SDL pour le rendu, qui est excellent en terme de performances. Ce qui me contraint à tout réécrire, et de plus dans un langage auquel je n’accroche pas du tout (le Lua) mais c’est le prix à payer pour les avantages suivants:

  • Anti Aliasing/Vsync natifs
  • Meilleure gestion de l’accèleration matérielle
  • Moteur physique intégré (Box2D, le même qu’Angry Birds d’ailleurs)
  • Système de particule intégré convainquant
  • Distribution Windows/Linux simplissime

Même s’il est plus récent,  LÖVE à déjà fait ses preuves puisqu’on trouve déjà quelques jeux commerciaux en basés dessus. (des petits trucs comme Snayke sur Desura ou Steam Greenlight).

Concept:

Le jeu sera un jeu de gestion, ce qui signifie qu’il faudra jouer sur plusieurs ressources et leur équilibrage pour ne pas perdre. Ma ligne directrice est de coller le plus possible à la réalité. C’est quelquechose qui me tient à coeur, car je reste persuadé qu’on peut s’amuser avec quelquechose de réaliste, pourvu que le gameplay soit bien pensé. Le joueur jouera une variété d’arbre, sélectionnable en début de partie. Le but du jeu est de faire de son éspèce, la plante dominante (comme dans la nature donc). Pour cela le joueur gagne des points. Un highscore game quoi.

Plus son arbre est grand, plus son arbre est ancien, plus on gagne de points. La petite nuance, c’est que les points ne sont comptabilisés que lorsque le joueur se reproduit (non, pas du sexe, avec des fruits), puisque c’est à ce moment qu’il transmet son patrimoine génétique.Au moment de se reproduire, le joueur à un choix. Il peut continuer à jouer dans sa plante, son score est alors sauvegardé et il continue la partie. Autrement, il peut choisir de s’incarner une des graines/fruits/spores générés pendant la reproduction et recommencer une plante, qui, évolution oblige, démarrera avec quelques bonus.

Gameplay:

En fonction de ses ressources le joueur pourra faire pousser des branches des racines et des feuilles sur sa plante.

Le joueur aura à jongler entre plusieurs ressources, et surtout entre deux mondes. À la surface, il devra s’adapter au rythme du jour et de la nuit ainsi qu’a celui des saisons. Cela influera sur la ressource “soleil” qu’il collecte. Dans ce mode, la ressource “soleil” sera collectée en fonction du nombre de feuilles disponibles et de l’ensoleillement. C’est à la surface aussi qu’on aura le plus d’évènements aléatoires (climat, animaux et autre) à gérer.

Sous terre, le fonctionnement sera différent: deux ressources, l’eau et les nutriments. L’eau est collectée uniformément, tandis que les nutriments seront concentrés sur des “spots” de ressources, pour forcer le joueur à pousser dans telle ou telle direction.

Une petite illustration en vidéo avec le prototype en Python/pygame:

Je vous conseille le plein écran pour apercevoir quelquechose.

YouTube Preview Image

Pourquoi j’en parle?

Parce que si vous avez regardé la vidéo ci-dessus vous avez du voir comme c’est moche.

Parce que j’arrive à un stade ou il va falloir prendre en considération la direction artistique du jeu, pour pouvoir coder comme il faut et pas faire des choses que je devrais défaire plus tard si cela ne colle pas avec la DA. Mes sprites sont HORRIBLES. Les curseurs, les branches, tout. Le seul truc qui passe c’est le fond d’écran parce que je l’ai piqué sur opengameart.

J’en parle parce que je suis tout sauf un artiste, et que j’aurais besoin d’un graphiste. Je n’ai aucune idée d’où en trouver un, j’ai essayé de fouiller un peu sur la toile, mais sans succès. Donc si vous avez une idée, un lien, un forum, un ami ou une motivation à tout épreuve à m’apporter, n’hésitez pas à me le dire, ce sera bienvenu.

Merci.

En bonus une autre vidéo plus ancienne, avec des sprites encore plus moches!

YouTube Preview Image

Autres idées (en vrac):

Achievements? Achievements!

Éspèces débloquables au fur à mesure

Multijoueur pour se la comparer (pas pour jouer en même temps)

Refaire le CSS du blog? Un jour…

Et bien sûr vous pouvez me contacter sur mon mail wefrag:

hube...@wefrag.com

Tu as un serveur hébergé chez toi? Une box qui change d’IP quand ça lui chante? Voici une solution pour y pallier.

Cet article fait suite à celui d’ecaheti du 16 Août concernant la configuration de son Raspberry Pi le changement d’IP de sa box.  Il a lui même réalisé une solution expliquée dans son article, mais celle-ci nécessite qu’un moteur PHP tourne sur le Rasp. Bien qu’il éxiste des outils pour gérer ça de façon automatique, il peut être préférable de le faire soi même, c’est pourquoi je propose ici une autre approche, moins gourmande pour le serveur local et plus simple à mettre en place à mon goût.

Voici la configuration d'origine

La configuration d'origine

Ingrédients:

  • Un serveur chez soi (Raspberry ou autre, peu importe)
  • Un serveur web avec PHP (free.fr en fournit gracieusement, ça fait parfaitement l’affaire)
  • Une box permettant le NAT (la redirection des ports)

L'objectif final: mise à jour de l'IP et redirection automatique

L'objectif final: mise à jour de l'IP et redirection automatique

Sur la box:

Rediriger les ports auquels ont veut accéder depuis l’extérieur vers l’adresse IP locale du serveur. Je ne rentrerais pas dans les détails, on trouve de très bons tutos un peu partout pour ça.

Espace Web 1/2 :

Comment connaître l’ip de ma box/mon serveur local?

La meilleure façon de connaître l’IP de mon serveur local est encore de regarder l’adresse d’origine d’une requête allant de mon serveur local à mon espace web.

Pour différencier une requête qui provient d’un visiteur “normal” de celles servant a mettre à jour l’adresse de ma box on va utiliser des variables POST. On va même “sécuriser” ça sous la forme d’un ensemble clé-valeur pour éviter que n’importe qui puisse changer l’IP de référence.
On va ensuite stocker l’IP d’ou provient la requête valide dans un fichier texte. Pour récupérer l’ip d’origine d’une requête en PHP, on utilise la variable $_SERVER["REMOTE_ADDR"]. C’est pratique d’autant plus qu’en ouvrant le fichier avec l’attribut "w+" on ne se préoccupe même pas de l’effacer, le nouveau contenu remplacera toujours l’ancien contenu du dit fichier.

$KEY      =    "le_serveur";
$VALEUR =    "c'est moi!";
$FICHIER =    "ip.txt";

if (isset($_POST[$KEY]) && $_POST[$KEY] === $VALEUR) {
$file = fopen($FICHIER, "w+");
fwrite($file, $_SERVER["REMOTE_ADDR"]);
fclose($file);
}

Voilà pour la partie mise à jour de l’IP côté PHP. Rien de bien méchant. Chaque fois qu’une requête contenant “le serveur=c’est moi” sera envoyée sur ce fichier, le fichier “ip.txt” sera mis à jour avec l’adresse d’origine. Il ne reste plus qu’a le faire régulièrement…

Serveur personnel:

La partie la plus facile. On va demander l’envoi de l’ensemble clé-valeur vers le serveur web. Pour gérer les tâches répétitives on utilise le cron, auquel on ajoute la ligne suivante:

user$: crontab -e #edition du fichier crontab avec votre editeur par défaut

#Ajout d'une ligne pour envoyer la requête toutes les 5 minutes
*/5 * * * * curl --silent -F le_serveur="c'est moi!" http://addresse/de/mon/fichier.php

Espace Web 2/2 :

Revenons à l’espace Web. Pour l’instant, le fichier PHP permet de mettre à jour l’IP de notre auto-hébergement automatiquement, mais si un visiteur arrive sur la page, il ne se passe rien (page blanche). À mon goût, il y a deux trucs sympas a faire pour un visiteur:

  • Une redirection transparente et instantanée vers le serveur local
  • Une liste des services proposés par le serveur local

Option 1: Redirection transparente

Sur le fichier côté serveur on va tout simplement… rediriger le navigateur, d’où le titre ! Pour cela il existe une fonction PHP: header(). Sans rentrer dans les détails, celle-ci ne fonctionnera si elle est utilisée en tête de fichier. Si on veut rediriger, il est important de l’appeler le plus tôt possible. (Typiquement: avant le code HTML s’il y en a). La fonction header prends comme paramètre une chaîne de caractères. Si elle content “location: http://uneurl“, elle va nous rediriger vers une adresse du type: http://uneurl. On déclare donc deux variables en tête de fichier: $PORT et $PROTOCOL.

Port étant le port sur lequel rediriger (par défaut :80 pour le web), et le protocole a utiliser (http://, https:// …). À nouveau je ne vais pas rentrer dans les détails, le port 80 et le http couvrant la majorité des cas.

<?php
$KEY        =    "le_serveur";
$VALEUR     =    "c'est moi!";
$FICHIER    =    "ip.txt";
$PORT       =    ":80";
$PROTOCOL   =    "http://";

if (isset($_POST[$KEY]) && $_POST[$KEY] === $VALEUR) {//Mise à jour de l'ip
$file = fopen($FICHIER, "w+");
fwrite($file, $_SERVER["REMOTE_ADDR"]);
fclose($file);
}else{//Redirection du client
$addresse   =   file_get_contents($FICHIER);
$addresse   =   $PROTOCOL . $addresse . $PORT;
header("location: $addresse");
}
?>

Protip: En PHP, lorsqu’on utilise des guillements doubles, on peut mettre nos variables directement entre les guillements. (Comme dans la ligne 15)

Option 2: Liste des services

Exemple de rendu de la liste de services

Exemple de rendu de la liste de services

On peut tout à fait s’arrêter ici et faire une page d’accueil sur le serveur local, permettant de lister les services dispos. Cependant, dans certains cas, il peut être utile de faire cela directement sur le serveur distant : pour économiser les (maigres) ressources d’un Raspberry Pi par exemple, et éviter d’y faire tourner un PHP juste pour afficher une page.

Pour lister les différents services, on va faire ça “en dur” ou de façon statique, pour éviter de scanner systématiquement tous les ports de votre serveur local à chaque visite. On va donc faire une liste des différents services que procure notre serveur. Cette liste va prendre la  forme d’un tableau associatif contenant le nom du service, et le port sur lequel il est publié.

Voici un exemple pour mon serveur.

$SERVICES    =    Array(
"Pages Web"=>":80",
"Streaming Video"=>":1234",
"Interface web qBittorrent"=>":8112",
"Interface web Transmission"=>":9091"
);

On va ensuite réaliser une boucle qui parcours ce tableau pour nous réaliser une liste au format HTML qu’il nous suffira ensuite d’afficher dans le corps d’une page HTML.

$IP = file_get_contents($FICHIER);
$listeHTML = "<ul>";
foreach($SERVICES as $nom => $port){
$URL = $PROTOCOL . $IP . $port;
$listeHTML .= "<li><a href='$URL'>$nom</a></li>";
}
$listeHTML .= "</ul>";

Pour les fénants, le code de la page HTML entière:


<?php
$KEY        =    "le_serveur";
$VALEUR     =    "c'est moi!";
$FICHIER    =    "ip.txt";
$PORT       =    ":80";
$PROTOCOL   =    "http://";
$SERVICES    =    Array(
"Web"=>":80",
"Streaming"=>":1234",
"qBittorrent"=>":8112",
"Transmission"=>":9091"
);

if (isset($_POST[$KEY]) && $_POST[$KEY] === $VALEUR) {
$file = fopen($FICHIER, "w+");
fwrite($file, $_SERVER["REMOTE_ADDR"]);
fclose($file);
}else{
$IP = file_get_contents($FICHIER);
$listeHTML = "<ul>";
foreach($SERVICES as $nom => $port){
$URL = $PROTOCOL . $IP . $port;
$listeHTML .= "<li><a href='$URL'>$nom</a></li>";
}
$listeHTML .= "</ul>";
}
?>
<!DOCTYPE HTML>
<html lang="en">
<head>
<link href='http://fonts.googleapis.com/css?family=Ubuntu' rel='stylesheet' type='text/css'>
<title>Mon chouette serveur Perso!</title>
<style type="text/css" media="screen">
*{
text-align:center;
}
h1{
font-family:'Ubuntu';
}
ul{
list-style-type:none;
}
</style>
</head>

<body>
<h1>Mon chouette serveur Perso...</h1>
<p>...est à votre disposition, et fournit les services suivants:</p>
<?php echo $listeHTML;?>
</body>
</html>
Voilà, en espérant avoir été clair et que cela resserve à d’autres.
Avec la démocratisation du Raspbery Pi, ce genre de petit script peut éviter des déboires à certains d’entre vous et vous permettre de vous concentrer sur des problèmes plus intérressants.

my Two Cents - site mobile inutile

Lundi 20 août 2012 à 1:11

“Tiens, je me suis fait 0.50€ pendant que j’étais aux toilettes, et déjà 1,54€ depuis mon premier café!”

Regis essayant myTwoCents

Écran de détail d'un compteur

Écran de détail d'un compteur

Après deux ans d’étude et d’inactivité bloguistique je retrouve le courage d’écrire quelque chose.

J’ai découvert récemment le framework jQueryMobile qui m’a paru franchement sympa et m’a donné envie de (re) jouer un peu avec le web mobile. J’ai donc réalisé une petite “webapp” pour l’occasion.

J’ai décidé réécrire un truc que j’adore: le module iGlande sur faineant.com: Une petite appli flash qui remplace le comptage de mouches par le comptage de brouzoufs quand on fout rien au boulot. Le but étant de se réjouir toute la journée en comptant combien on gagne chaque seconde.

Comme c’est du flash, et que mon téléphone n’aime pas ça, c’était l’occasion.

Pour ceux qui veulent essayer et s’amuser 5 minutes c’est par ici, pour les apprentis magiciens qui veulent des détails sur la réalisation, bonne lecture.

Je présente ici la partie stockage des données et calcul des compteurs. Pour plus de lisibilité la partie purement jQueryMobile fera l’objet d’un autre article.



TL;DR: scanne ça pour tester.

TL;DR: scanne ça pour tester.

Cahier des charges

Je veux :

  • savoir combien je gagne en temps réel
  • garder en mémoire les paramètres (compteurs, options…)
  • que mon salaire soit compté même quand je ne suis pas sur le site
  • pouvoir suivre plusieurs compteurs en parallèle (celui de ma femme, de ma dernière sieste et de mon dernier café)

Je ne veux pas:

  • de base de donnée (pas envie de me casser les pieds)
  • que les utilisateur puissent voir les compteurs des autres
  • de login  / mdp

Petite nuance par rapport au module iGlande: je ne compte pas le salaire au 35H, mais en heures réelles, afin que le compteur puisse continuer a tourner la nuit. Ça fait à peu près du 720H/Mois.

Au final, on code que dans 2 fichiers, le reste, c'est des frameworks et des plugins

Au final, on code que dans 2 fichiers, le reste, c'est le framework et les plugins

Les outils

Pour réaliser l’appli je vais utiliser:

  • du jQueryMobile (c’était le but après tout)
  • un plugin jQuery pour gérer les cookies
  • du jQuery tout court
  • un bon IDE et du café

Le stockage des données

Pour ne pas avoir à gérer de base de données et de login/mdp j’ai décidé de stocker les données côté client, dans son navigateur. En me réunissant avec moi même j’ai pensé a deux solutions:

les cookies

Les cookies sont ces sales petits trucs qui se stockent dans votre navigateur lorsque vous visitez des sites. Ça sert aussi bien a cibler la publicité qu’a connaître vos habitudes de surf nocturnes. Typiquement la case “se rappeller de moi” quand vous vous loguez sur un site,  utilise un cookie.

Les plus:

  • Tous les navigateurs les prennent en charge

Les moins:

Tous les navigateurs s’en méfient. Le stockage d’un cookie est effectué pour une durée donnée. Le problème c’est que l’abus de beaucoup de sites a conduit les navigateurs à êtres drastiques avec les cookies. Aucun moyen de savoir si la durée de stockage sera respectée, ou même si le navigateur acceptera de garder les cookies ne serais-ce que 20 secondes après la fermeture de la page.

le localStorage

Le localStorage c’est l’évolution logique du cookie, qui est apparu avec la norme HTML5. C’est encore peu utilisé et peu pris en charge, c’est à la fois un avantage et un inconvénient, les navigateurs et autres logiciels “nettoyeurs de trace” ont moins tendance a supprimer sauvagement le localStorage que les cookies.

Plus:

  • Plus rapide que les cookies
  • Pas de limitation de durée

Moins:

  • Pas géré par tous les navigateurs (notamment mobiles)

Écran principal

L'écran d'accueil

Comme souvent quand il faut choisir, j’ai décidé de prendre les deux solutions. Mon site devra donc regarder si le local Storage est disponible, et si ce n’est pas le cas, utiliser les cookies. Pour cela c’est très simple, le test suivant va nous dire pour le navigateur courant, si le localStorage est utilisable:

if (localStorage) {
debug("J'ai le localStorage");
}else{
debug("Je vais devoir utiliser les cookies...");
}

Maintenant la question des compteurs: comment faire compter un compteur côté client, lorsque que le client n’est pas sur la page?

C’est très simple: on ne peut pas.

On va donc fonctionner différemment. On stocke l’heure de démarrage du compteur, lorsqu’on voudra connaître l’argent gagné depuis, on fera la différence avec l’heure actuelle. En pratique ça donne ça:

On déclare des variables globales en tête de fichier

/**
* Global vars
*/
var debugConsole    =   true;//TODO: affiche les infos dans la console quand vrai, passer a false en prod
//Paramètres
var CURRENCY        =   "&euro;";
var LOCAL_STORAGE   =   false;
var TICK            =   false;
var DISPLAY_BUTTON  =   false;
var NOTIF           =   false;
var NOTIF_CAPABLE   =   false;
var TIMERLAP        =   10;
//Données compteurs
var counterNames    =   Array();
var counterDates    =   Array();
var counterIncomes  =   Array();

Puis on les attribue en fonction de la détection du navigateur:

La dernière ligne de chaque bloc, écrit un texte dans l’écran de config afin d’informer l’utilisateur de la technique de stockage utilisée.

if (localStorage) {
LOCAL_STORAGE   =   true;
CURRENCY        =   localStorage.getItem("CURRENCY")==="true"       ?true:CURRENCY;
TICK            =   localStorage.getItem("TICK")==="true"           ?true:TICK;
DISPLAY_BUTTON  =   localStorage.getItem("DISPLAY_BUTTON")==="true" ?true:DISPLAY_BUTTON;
NOTIF           =   localStorage.getItem("NOTIF")==="true"          ?true:NOTIF;
$("#localStorageStatus").html("Great! Your browser can use localStorage. You maybe won't see the difference, but I will!");
debug(TIMERLAP);
} else {
LOCAL_STORAGE   =   false;
CURRENCY        =   $.cookie("CURRENCY")==="true"       ?true:CURRENCY;
TICK            =   $.cookie("TICK")==="true"           ?true:TICK;
DISPLAY_BUTTON  =   $.cookie("DISPLAY_BUTTON")==="true" ?true:DISPLAY_BUTTON;
NOTIF           =   $.cookie("NOTIF")==="true"          ?true:NOTIF;
$("#localStorageStatus").html("Your browser doens't have a localStorage. Data will be stored in cookies. If they get erased, you'll loose your data");

Du coup, chaque ajout de compteur prendra simplement la forme :

//Lecture des données
var name = $("#counterName").val();
var income = $("#monthIncome").val();
var startDate = new Date().getTime();
//Reset des champs de saisie
$("#counterName").val("");
$("#monthIncome").val("");

//Intégration dans les tableaux de compteurs
counterNames.push(name);
counterDates.push(startDate);
counterIncomes.push(income);
saveCounterValue();

La fonction saveCounterValue() se chargeant simplement de sauvegarder les tableaux au bon endroit selon la valeur de la variable LOCAL_STORAGE vue plus haut.

Ajout d'un compteur

Ajout d'un compteur

Le Calcul

Pour calculer combien d’argent on a gagné on boucle sur chaque compteur. On va alors déterminer la différence entre la date de départ de celui-ci et la date actuelle.

//Calcul de la différence entre maintenant et le début
delta = new Date().getTime() - counterDates[i];
//Conversion du revenu mensuel en revenu milliseconduel

Puis on va réduire un salaire mensuel, à un salaire par milliseconde. On commence par se demander combien vous gagnez par an (pour pouvoir gérer un revenu moyen indépendamment du fait que l’année soit bissextile ou non), pour le diviser ensuite par le nombre de milliseconde d’une année.

function monthlyToMillisecIncome(income){
var DAYS_PER_YEAR       =   365.25;
var MONTH_PER_YEAR      =   12;
var HOURS_PER_DAY       =   24;
var MINUTES_PER_HOUR    =   60;
var SEC_PER_MINUTE      =   60;
var MILLISEC_PER_MINUTE =   1000;
return income * MONTH_PER_YEAR / DAYS_PER_YEAR / HOURS_PER_DAY / MINUTES_PER_HOUR / SEC_PER_MINUTE / MILLISEC_PER_MINUTE;
}

On n’a plus qu’a appeler la fonction et à formater la chaîne à afficher…

millisecIncome = monthlyToMillisecIncome(thatIncome);
sofar = delta * millisecIncome;
sofar = Math.round(sofar * 100) / 100;//Arrondi a 2 décimales

//Formattage pour l'affichage du temps écoulé
tmpDate = new Date(delta);
elapsed = tmpDate.getUTCHours() +":"+tmpDate.getUTCMinutes()+ ":"+tmpDate.getUTCSeconds();

Voilà pour la partie backoffice de l’application. C’est loin d’être parfait, mais c’est fonctionnel et testable en ligne. Je compte encore passer quelques jours dessus si je trouve des choses intéressantes à y faire.

La partie jQueryMobile fera l’objet d’un prochain article.

Fun fact: j’ai gagné 1,87€ en rédigeant ce post.

TODOLIST:

  • Des notifications compatibles avec les  mobiles?
  • Une animation de l’icône lors d’une notification?
  • Une version multilingue?
  • Des supers idées proposées par les nofragés?

Avec un icône dédié pour mettre sur son menu iPhone...

Avec un icône dédié pour mettre sur son menu iPhone...

Ayant enfin, après un cursus plus qu’aléatoire commencé mes études en informatique. Du coup j’ai développé par un après midi de temps libre deux pages PHP pour stocker mes ebooks en ligne, afin que mes amis lisant sur iPhone puisse se servir dans ma petite collection. C’est un tout petit truc sans ambition, mais étant donné la rareté de la documentation pour iui sur internet, cela ne fera de mal a personne.

Un simple répertoire ftp aurait suffit, mais ça n’a rien de convivial ni de pratique. Lorsque l’on utilise Stanza (l’application gratuite la plus répandue pour lire sur iPhone), cela nécessite de cliquer sur ajouter un catalogue, choisir l’option web, taper l’adresse et galérer un peu avec le zoom pour sélectionner le livre que l’ont veut télécharger.

J’ai donc été chercher du coté des librairies iui de Joe Hewitt. En l’absence de documentation j’ai vraiment fait un truc balbutiant et non fini, mais qui à le mérite de fonctionner et de faire ce que j’attends de lui.

But : lister les fichiers d’un répertoire et de ses sous répertoires et faire un lien vers ceux-ci permettant un import direct dans Stanza. Le contenu des sous répertoires apparaîtra dans une sous-liste.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Berru2 - iPhone</title>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<link rel="apple-touch-icon" href="../err/iui/iui-logo-touch-icon.png" />
<meta name="apple-touch-fullscreen" content="YES" />
<style type="text/css" media="screen">@import "../err/iui/iui.css";</style>
<script type="application/x-javascript" src="../err/iui/iui.js"></script>
</head>

Dans le header on inclue les fichiers de la librairie iui préalablement installée  sur le ftp, ici dans ../err/iui. Le fichier iui.css qui permet d’utiliser les class qui donneront le look iPhone et le iui.js qui permet de faire des transitions animées entre les liens : le petit effet de glissement que l’on à lorsque l’on passe d’un menu à un sous menu dans l’iphone OS.  On donne le lien vers l’icône qui sera utilisé quand l’utilisateur crée un lien vers le site, au format PNG et en 57px par 57px.

Les fichiers .epub sont des fichiers ebooks faciles à lire sur iPhone, de plus lorsqu’un iPhone/iPod Touch à le logiciel Stanza d’installé les liens utilisant le protocole epub:// permettent de dire à l’iPhone de lancer Stanza et de commencer l’importation du fichier vers lequel le lien pointe.

<ul id="home" title="eBooks" selected="true">

<? //----Boucle d'affichage des FOLDER
$folder = "./";
$dossier = opendir($folder);
while ($Fichier = readdir($dossier)) {
if(is_dir($Fichier) && $Fichier != '.' && $Fichier != '..' ){
$nomFichier = $folder.$Fichier;
$nomFichier2 = substr(str_replace('./','',$nomFichier),0,20);
echo '<li><a href="#_'.$nomFichier2.'" target="_self">'.$nomFichier2.'</a></li></br>';

}
}
closedir($dossier);
?>

<li> <a href='#root'> Local </a></li>
</ul>

On débute le contenu de la page lui même : la classe toolbar permet d’afficher le haut de la page d’une appli iPhone, et à lui intégrer un bouton retour lorsque l’on est dans une sous liste. La première boucle en PHP permet de regarder dans le dossier actuel et d’y trouver tous les répertoires. Pour chaque répertoire trouvé, un lien relatif vers une ancre (#_nom_du_répertoire) est créé. Le tout est placé dans des balises <ul> </ul> afin d’apparaître dans une même page, la page home qui sert de page d’accueil. Remarquez la présence du lien vers l’ancre #_root appellélocal“. C’est le lien qui servira à entrer dans le sous menu qui liste les fichiers à la racine du répertoire.

<?php //Affichage du contenu EPUB des sous répertoires
$folder = "./";
$dossier = opendir($folder);
while ($Fichier = readdir($dossier)) {
if(is_dir($Fichier) && $Fichier != '.' && $Fichier != '..' ){
$nomFichier = $folder.$Fichier;
$nomFichier2 = substr(str_replace('./','',$nomFichier),0,20);
echo '<ul id="'.$nomFichier2.'" title="'.$nomFichier2.'">';
$sdossier = opendir($nomFichier.'/');
while ($sFichier = readdir($sdossier)) {
if (substr($sFichier,-4,4)== 'epub') {
$nomsFichier = $folder.$sFichier; // Attention $nomFichier != $nomsFichier
$nomRep = opendir('../');
$nomsFichier2 = str_replace('./', 'epub://berru2.free.fr/', $nomsFichier);
$nomsFichier3 = str_replace('./','',$nomsFichier);
$urlFichier = $nomFichier2.'/'.$nomsFichier3;
$urlFichierStanza = 'epub://berru2.free.fr/ebooks/'.$urlFichier;
echo '<li><a href="'.$urlFichierStanza.'" target="_self">'.str_replace('_',' ',substr($nomsFichier3,0,30)).'</a></li></br>';
}
}
echo '</ul>';

}
}
?>

<ul id="root" title="Racine">

Ici on exécute une boucle qui ouvre les sous répertoires du répertoire courant à la recherche des fichiers .epub
Tous ces fichiers seront donc listés entre deux balises <ul></ul> pour apparaître à chaque fois dans un sous menu portant le nom du répertoire dans lequel on les à trouvés.
Enfin, on remplace le protocole http:// du lien vers le fichier par le protocole epub://.

</pre>
<ul id="root" title="Racine">
<?php
//-------Boucle d'affichage des fichiers EPUB
$folder = "./";
$dossier = opendir($folder);
while ($Fichier = readdir($dossier)) {
if (substr($Fichier,-4,4)== 'epub') {
$nomFichier = $folder.$Fichier;
$nomFichier2 = str_replace('./', 'epub://berru2.free.fr/', $nomFichier);
$nomFichier3 = substr(str_replace('./','',$nomFichier),0,20);
echo '<li><a href="'.$nomFichier2.'" target="_self">'.$nomFichier3.'</a></li></br>';
}
}
closedir($dossier);
?>
</ul>

</body>

La dernière boucle parcours les fichiers du répertoire courant à la recherche des fichiers .epub. Même principe que plus haut, on remplace le protocole http:// par epub:// et on stocke tous les liens relatifs dans le sous menu appelé “Local”.

Pour finir, une petite redirection, en javascript sur ma home afin de rediriger les possesseurs d’iPhone/iPod touch vers la page que l’on viens de voir, sinon vers une page pour permettre d’uploader des fichiers .epub.


<script type="text/javascript">
if (navigator.userAgent.indexOf('iPhone') != -1)
{
if(confirm('Vous êtes sur un iPhone/iTouch, voulez vous accèder au catalogue ebook?'))
window.location="http://berru2.free.fr/ebooks/iphone.php";
}
else if (navigator.userAgent.indexOf('iPod') != -1)
{
if(confirm('Vous êtes sur un iPhone/iTouch, voulez vous accèder au catalogue ebook?'))
window.location="http://berru2.free.fr/ebooks/iphone.php";
}
</script>

Vous pourrez tester la page en vous rendant à l’adresse suivante si vous avez un iPhone : http://berru2.free.fr/

Et si vous n’avez pas d’iPhone vous pourrez essayer la page (dont la mise en forme sera proche de ce qu’on voit sur iPhone sans être identique) ici. Par contre les liens vers le ebooks ne seront du coup pas fonctionnel à moins que vous n’ayez associé un programme au protocole epub:// sur votre machine.

Si vous avez des suggestions concernant le code ou les fonctionnalités, elles sont les bienvenues, c’est toujours formateur d’avoir un retour.

L'aspect final en version iPhone.

L'aspect final en version iPhone.

Edit: Les bugs remontés par Caroline sont corrigés, et les underscore dans les menus sont désormais masqués. Le code ci dessus est mis à jour.