Kattelin noita esimerkki oppaita PHP:stä ja ne näyttivät olevan erinomaisia.
Yksi asia aihe alua jäi kuitenkin epäselväksi ja se on PHP:n käyttö internet ympäristön ulkopuolella.
Eli noissa oppaissa tuli hyvin ilmi, että miten voin mm. kirjoittaa palvelimen tiedostoon, käyttää cookieita ja Tietokantoja, mutta epäselväksi jäi, voiko palvelimeenkin kirjoittaa jonkun oman itsenäisen php sovelluksen. Se voisi ottaa vastaan asiakkaiden kyselyitä, mutta se myös toimisi samalla itsenäisesti riippumatta siitä, onko kellään asiakkaista istunto kesken. Se tekisi kaiken laskennan, mitä täytyy tehdä mm. moninpeleissä.
Eli toisin sanoen serveri koodin kirjoittaminen, miten se tapahtuu? onko se joku php exe tiedosto, vaiko pitääkö käyttää apuna jotain muuta kieltä?
Eräs vaihtoehto on antaa skriptille komento ignore_user_abort( true );
. Voit myös käyttää socketteja, joilla voit tehdä vaikkapa oman peliserverin (kts. ensimmäinen esimerkki manuaalisivulla). Vakaudesta en sitten osaa mitään sanoa.
Paulus M kirjoitti:
Eli noissa oppaissa tuli hyvin ilmi, että miten voin mm. kirjoittaa palvelimen tiedostoon, käyttää cookieita ja Tietokantoja, mutta epäselväksi jäi, voiko palvelimeenkin kirjoittaa jonkun oman itsenäisen php sovelluksen. Se voisi ottaa vastaan asiakkaiden kyselyitä, mutta se myös toimisi samalla itsenäisesti riippumatta siitä, onko kellään asiakkaista istunto kesken. Se tekisi kaiken laskennan, mitä täytyy tehdä mm. moninpeleissä.
Kysymys on melkoisen joten koitan arvata, mitä haluat tehdä. Arvauksen pohjana on se, että tämä jotenkin liittyy Travian-klooniprojektiisi :-)
Eli siis php-scriptejä on mahdollista suorittaa suoraan komentotulkista (Linuxissa komennolla:
php [filun_nimi]
man php kertoo lisää.. Ja kun skriptin voi ajaa komentotulkista käsin, voi sen myös ajastaa crontabilla.
Jos ihan oikeasti tarvitset kokoajan päällä olevan prosessin, itsenäisen ohjelman, ei sitä kannata alkaa väsäämään skripti kielellä. Moneen php-venyy, mutta siinä se on vähän kömpelö :D
Edit: Heh, on se hyvä, että Blaze löysi tuon melkein bittiavaruuteen hukkaamani lauseen :D
Blaze kirjoitti:
Sullahan on jo HTTP-serveri (Apache), hyödynnä sitä.
LaNu kirjoitti:
Jos ihan oikeasti tarvitset kokoajan päällä olevan prosessin, itsenäisen ohjelman, ei sitä kannata alkaa väsäämään skripti kielellä.
Ja sikäli kun peliä tunnen, Travian-klooniin ei tarvi moista. Sullahan on jo HTTP-serveri (Apache), hyödynnä sitä.
Olet sinä LaNu aika veitikka arvaamaan!:D
Vastasit vallan mainiokkaasti kysymykseeni!
Mutta sanotaan siis, että jos olisin väsäämääsässä tätä travianin kloonia, niin eikössiinä täydy olla kokoajan palvelin prossu päällä. Ajatellaan, että kun tehdään hyökkäys, niin se tapahtuu tiettynä ajankohtana, vaikkei hyökkääjä tai puolustaja olisikaan online tilassa. Tottakai hyökkäyksen voi simuloida jonkun muun käyttäjän prossulla, mutta kuvittelisin että siinä ainakin on joki palvelin prossu, joka laskee kokoajan jotakin.
Eli venyykö tämä PHP niin paljon, että sitä voi pitää kokoajan päällä?
lainaus:
Jos ihan oikeasti tarvitset kokoajan päällä olevan prosessin, itsenäisen ohjelman, ei sitä kannata alkaa väsäämään skripti kielellä. Moneen php-venyy, mutta siinä se on vähän kömpelö :D
vaiko mitä tarkalleen ottaen tarkoittaa toi HTTP serverin hyödyntäminen? Enhän voi sinne mitään tietokantaa perustaa, vai voinko?
ps. Huvittaa toi termi "travianin klooni"...hehe, pitäisköhän laittaa se pelin nimeksi, niin asiakasvirta olisi taattu:D
Ei vaiskaan, en nyt sentään mitään kloonia oo väsäämässä. Travianista olen vain oppinut sen, että mielenkiintoisen pelin voi tehdä, vaikkei olisikaan maailman paras koodari tai pelissä ei olisi hienoa grafiikkaa.
Todettakoon alkuun, etten ole traviania pelannut :)
Paulus M kirjoitti:
Mutta sanotaan siis, että jos olisin väsäämääsässä tätä travianin kloonia, niin eikössiinä täydy olla kokoajan palvelin prossu päällä. Ajatellaan, että kun tehdään hyökkäys, niin se tapahtuu tiettynä ajankohtana, vaikkei hyökkääjä tai puolustaja olisikaan online tilassa. Tottakai hyökkäyksen voi simuloida jonkun muun käyttäjän prossulla, mutta kuvittelisin että siinä ainakin on joki palvelin prossu, joka laskee kokoajan jotakin.
Voiko pelissä tapahtua hyökkäys ilman, että hyökkääjä http-pyynnöllä sitä käynnistää (linkkiä/lomaketta käyttämällä)? Tai jos voikin, niin eikö tuollaisen kuitenkin voi sijoittaa jostain ajastetusta scriptistä "laukeamaan"?
lainaus:
vaiko mitä tarkalleen ottaen tarkoittaa toi HTTP serverin hyödyntäminen? Enhän voi sinne mitään tietokantaa perustaa, vai voinko?
Ainakin siihen rakentamaasi testiympäristöön MySQL-palvelimen asensit. En oikein voi kuvitella, että mitään Travianin suuntaista ilman tietokantaa pystyisi pyörittämään. Vahva veikkaukseni on, että Travianin peli on "käynnissä" tietokantapalvelimella: pelin tilaa säilötään siellä ja se muuttuu ajastetuilla ja käyttäjien käynnistämillä skripteillä.
Eli siis HTTP-palvelu, Apache, on palvelimella kokoajan päällä ja käsittelee käyttäjän pyyntöjä ja lähettää vastauksia. Tietokantapalvelin, MySQL on myös kokoajan käynnissä palvelimella ja sieltä saadaan aina tarvittaessa tieto pelitilanteesta, kun joku sitä kaipailee. Tuossa on sellaiset kivat pilarit pelille ;-) Enää tarvitaan pelimekaniikan hoitavat skriptit ja käyttäjälle sivut kasaavat skriptit...
Edit: Hmm.. yllä oleva kappale lakimiesjargoniksi, vähän kermaa innovaation kuorrutukseksi ja jenkkilään patenttihakemus vetämään? Ei ole voinut kukaan ehtiä! :D
lainaus:
ps. Huvittaa toi termi "travianin klooni"...hehe, pitäisköhän laittaa se pelin nimeksi, niin asiakasvirta olisi taattu:D
Enhän sanonut Travianin klooni, vaan Travian-klooni. Noilla on peleistä puhuttaessa hiukan eri kaiku ainakin minun korvissani :-) Jos et kuitenkaan ole mitään Travianin suuntaista tekemässä, niin pelisi on kai pelityypiltään selain pohjainen MMOG tjsp.
P.S. Minusta Travianin grafiikka on silmiä hivelevää, vaikken koskaan ole peliä kokeillut ;-)
Paulus M kirjoitti:
Mutta sanotaan siis, että jos olisin väsäämääsässä tätä travianin kloonia, niin eikössiinä täydy olla kokoajan palvelin prossu päällä. Ajatellaan, että kun tehdään hyökkäys, niin se tapahtuu tiettynä ajankohtana, vaikkei hyökkääjä tai puolustaja olisikaan online tilassa. Tottakai hyökkäyksen voi simuloida jonkun muun käyttäjän prossulla, mutta kuvittelisin että siinä ainakin on joki palvelin prossu, joka laskee kokoajan jotakin.
Kun käyttäjä laittaa jonkin rakennuksen rakentumaan, tapahtuma lisätään jonoon, jossa kaikki tapahtumat ovat aikajärjestyksessä(valmistumisajan mukaan). Ja sitten, kun joku käyttäjä urkkii/lisää tietoja, suoritetaan ne jonon tapahtuma, jotka olisi pitänyt tapahtua siihen mennessä.
Ps. En itsekään ole traviania pelaillut, mutta tribalwars on sitäkin tutumpi :)
LaNu kirjoitti:
Voiko pelissä tapahtua hyökkäys ilman, että hyökkääjä http-pyynnöllä sitä käynnistää (linkkiä/lomaketta käyttämällä)? Tai jos voikin, niin eikö tuollaisen kuitenkin voi sijoittaa jostain ajastetusta scriptistä "laukeamaan"?
Joo, eli pitää klikata, että hyökkää kylään ja sitten kestää x aika määrä ja taistelu tapahtuu. Ilmeisesti laskenta tapahtuu sitten tällä jonotusperiaatteella mistä Gaxx asiantuntevasti minua valaisi, eli vissiin siis viimekädessä kaikki prosessointi tapahtuu käyttäjien prossuilla.
LaNu kirjoitti:
Ainakin siihen rakentamaasi testiympäristöön MySQL-palvelimen asensit. En oikein voi kuvitella, että mitään Travianin suuntaista ilman tietokantaa pystyisi pyörittämään. Vahva veikkaukseni on, että Travianin peli on "käynnissä" tietokantapalvelimella: pelin tilaa säilötään siellä ja se muuttuu ajastetuilla ja käyttäjien käynnistämillä skripteillä.
Voi olla, että puhut täyttä asiaa. Eli täytyy vaan oppia hallitsemaan nokkelasti näitä tietokantoa käyttäjien prossuja hyväksi käyttäen.
lainaus:
Edit: Hmm.. yllä oleva kappale lakimiesjargoniksi, vähän kermaa innovaation kuorrutukseksi ja jenkkilään patenttihakemus vetämään? Ei ole voinut kukaan ehtiä! :D
Em ymmärtänyt läppää :D..hehe. No toivottavasti se ei ollut liian hyvä läppä, muuten jäis harmittaa pahastikkin...
Joo, mutta kiitos vastauksiasta! Nyt alkaa vaan tiivis opettelu ja saa nähdä kuinka kauan jaksan tästä taas innostua. Mutta melko todennäköistä on, että täällä alkaa viliseen tuon tuostakin kysymyksiä PHP:stä ja MySQL:stä.
Paulus M kirjoitti:
LaNu kirjoitti:
Voiko pelissä tapahtua hyökkäys ilman, että hyökkääjä http-pyynnöllä sitä käynnistää (linkkiä/lomaketta käyttämällä)? Tai jos voikin, niin eikö tuollaisen kuitenkin voi sijoittaa jostain ajastetusta scriptistä "laukeamaan"?
Joo, eli pitää klikata, että hyökkää kylään ja sitten kestää x aika määrä ja taistelu tapahtuu. Ilmeisesti laskenta tapahtuu sitten tällä jonotusperiaatteella mistä Gaxx asiantuntevasti minua valaisi, eli vissiin siis viimekädessä kaikki prosessointi tapahtuu käyttäjien prossuilla.
Prosessointi tapahtuu tottakai serverillä, mutta tapahtumia suoritetaan vain silloin, kun joku tutkii/lisää tietoja serverille.
Esim. Kun joku käyttäjistä haluaa rakentaa talon, lisätään se oikeaan kohtaan jonoa ja samalla tarkastetaan, pitäisikö jotain muita(jo jonossa olleita) tapahtumia olla suoritettuna(esim jokin muu rakennus valmistui edellisen scriptin ajonkerran jälkeen).
Edit: ja vielä rautalangasta varmuuden vuoksi.
Pelaaja A haluaa rakentaa talon. Tämä tapahtuu klo 13:00. Talon rakentaminen kestää yhden tunnin, eli talon pitäisi olla valmis klo 14:00. Klo 13:59 käyttäjä B lataa serveriltä maailman kartan ja samalla serveri tarkastaa pitäisikö jotain tapahtumia olla suoritettuna. Havaitaan, että ei, sillä talon pitäisi valmistua vasta klo 14:00. Klo 14:01 käyttäjä C tutkii omaa kyläänsä, jolloin hän lataa sen tiedot serveriltä. Samalla serveri tarkistaa, pitäisikö jotain tapahtumia olla suoritettuna ja toteaa, että kyllä: Käyttäjän A rakennus. Tällöin serveri päivittää talon rakennetuksi. Klo 14:00 ja klo 14:01 välisenä aikana kukaan käyttäjä ei ole penkonut serveriä, joten ei ole mitään väliä, vaikka sen tiedot eivät olisi ihan ajan tasalla. Huom! Tarkastelu, pitäisikö jokin tapahtuma olla tapahtunut, kannattaa yleensä tehdä ennen varsinaisen käyttäjän pyyntöä(esim talon rakennus), jotta tapahtumat tapahtuvat varmasti oikeassa järjestyksessä.
Eli toisin sanoen, jos tekisin klooni travianin, niin joudunkin koodaamaan jonkun exe tiedoston omalle koneelleni, jota pidän päällä? Vai teenkö jonku prosessin, jota sitten HTTP pyörittää?
Mikä on fiksuin lähestymistapa travian kaltaisessa softassa?
Paulus M kirjoitti:
Mikä on fiksuin lähestymistapa travian kaltaisessa softassa?
Tuo, mitä Gaxx kerto.
Soap server/client on helpompi kuin socket ja xml on päivän sana. Cronilla saa ihmeitä myös aikaan, mutta Zend Platform tuotteessa on job_queue joka tekee saman kuin cron, mutta osaa myös hanskata sen, että prosessi tulee oikeasti tehtyä (jota taas cron ei osaa).
-W-
Siis et tarvitse yhtäkään koko ajan pyörivää prosessia, vaan aina kun joku käyttäjä kirjautuu sisään/rakentaa/tekee mitä tahansa pelissä, niin tarkistetaan pitäisikö mitään olla tehtynä kellonajan mukaan, tämä "jono" voi olla esim. tietokannassa.
Mutta mites tämä jono onnistuisi tehdä?
Hakoulinen kirjoitti:
Mutta mites tämä jono onnistuisi tehdä?
Yritin väsätä jonkin hienon esimerkin, mutta siitä tuli niin sekava, että sitä ei kehtaa julkaista.
Tyydyn siis toteamaan, että homma onnistuu luultavimmin näppärimmin linkitetyllä listalla. Kaikki listan alkiot sijaitsevat sikin sokin epäjärjestyksessä muistissa. Jokainen alkio sisältää kuitenkin osoitteen listan seuraavaan alkioon. Tällöin, kun tiedetään listan ensimmäinen alkio, pystytään käymään läpi kaikki listan alkiot. Listan viimeinen alkio osoittaa sitten vaikka NULLiin, jotta tiedetään sen olevan viimeinen.
Tapahtuman lisääminen listaan on helppoa. Esimerkiksi, kun halutaan lisätä listassa viidennen ja kuudennen tapahtuman väliin jokin tapahtuma, laitetaan lisättävän alkion seuraavan_osoittaja osoittamaan listan kuudenteen alkioon ja viides alkio osoittamaan lisättävään alkioon.
Homma onnistuu periaatteessa taulukoillakin, mutta ei ole läheskään yhtä tehokas varsinkaan, kun jonon pituus on suuri. Joutuisimme silti tutkimaan jonoa aina alkio kerrallaan järjestyksessä sen alkupäästä.
Gaxx kirjoitti:
Hakoulinen kirjoitti:
Mutta mites tämä jono onnistuisi tehdä?
Yritin väsätä jonkin hienon esimerkin, mutta siitä tuli niin sekava, että sitä ei kehtaa julkaista.
Tyydyn siis toteamaan, että homma onnistuu luultavimmin näppärimmin linkitetyllä listalla. Kaikki listan alkiot sijaitsevat sikin sokin epäjärjestyksessä muistissa. Jokainen alkio sisältää kuitenkin osoitteen listan seuraavaan alkioon. Tällöin, kun tiedetään listan ensimmäinen alkio, pystytään käymään läpi kaikki listan alkiot. Listan viimeinen alkio osoittaa sitten vaikka NULLiin, jotta tiedetään sen olevan viimeinen.
Tapahtuman lisääminen listaan on helppoa. Esimerkiksi, kun halutaan lisätä listassa viidennen ja kuudennen tapahtuman väliin jokin tapahtuma, laitetaan lisättävän alkion seuraavan_osoittaja osoittamaan listan kuudenteen alkioon ja viides alkio osoittamaan lisättävään alkioon.
Homma onnistuu periaatteessa taulukoillakin, mutta ei ole läheskään yhtä tehokas varsinkaan, kun jonon pituus on suuri. Joutuisimme silti tutkimaan jonoa aina alkio kerrallaan järjestyksessä sen alkupäästä.
Laita sitä esim. vaan, selvittäis vähän paremmin.
Siis jokainen tapahtuma sisältää myös tiedon siitä, mikä on seuraava tapahtuma, ja lisäksi pidetään jossain tietoa ensimmäisestä ja viimeisestä tapahtumasta. Pseudokoodia:
tiedostosta haettavat muuttujat: ensimmainen, viimeinen; koodattavat funktiot: varaa_vapaa_id(), suorita_tapahtuma(), poista_tapahtuma(); funktio lisää_tapahtuma: id = varaa_vapaa_id(); tapahtumat[id] = uusi_tapahtuma; tapahtumat[id]->seuraava = tyhja; if (ensimmainen == tyhja): ensimmainen = id; else: tapahtumat[viimeinen]->seuraava = id; viimeinen = id; funktio hoida_tapahtumat: while (ensimmainen != tyhja && tapahtumat[ensimmainen]->aika < time()): seuraava = tapahtumat[ensimmainen]->seuraava; suorita_tapahtuma(ensimmainen); poista_tapahtuma(tapahtumat[ensimmainen]); ensimmainen = seuraava; if (ensimmainen == tyhja): viimeinen = tyhja
Eikös noiden tapahtumien säilöminen ois helpointa ihan suoraan MySQL:n kanssa? Jokaiseen tapahtumaan liitettäisiin (auto_increment) ID-numero yksilöijäksi sekä pvm/kellonaika (eli datetime-tyyppinen) sarake. Sitten vaan kysellään uusimmat tapahtumat SELECToimalla WHERE tapahtuman aika on vähemmän kuin nykyhetki, suoritetaan tapahtumien vaatimat toimenpiteet yksi kerrallaan ja DELETEoidaan kyseiset tapahtumat jonotaulusta.
Sivuhuomautuksena: tuo kaikki tulisi tietysti tehdä transaktiossa, jottei esimerkiksi tapahtuman suoritus tallentuisi kantaan ilman, että tapahtumaa on poistettu jonosta jne. MySQL:n ohjesivuilta löytyy tietoa siitä, miten transaktiot saadaan toimimaan. Huomautettakoon heti, että taulut täytyy sitä varten luoda InnoDB-muotoon. Manualista löytää myös jonkin verran erikoisia käyttötapauksia, jotka rikkovat transaktiot antamatta mitään virheilmoitusta. MySQL osaa toisinaan olla tässä suhteessa aika ärsyttävä.
Paulus M kirjoitti:
- -
Laita kaikki tapahtumat tietokantaan.
Sitten kirjoitat erillisen ohjelman joka käy silmukassa tietokantaa lävitse.
Vähän tähän tapaan (pseudokoodia en viitsinyt tehtä, joten kaivoin omasta, kesken jätetystä traviankloonista), kieli C:
while(!quit){ time(&aika); //Aloitetaan tapahtumien suoritus mysql_query(connection, "SELECT MIN(aika) FROM events ORDER BY id ASC;"); res1 = mysql_use_result(connection); while((row1 = mysql_fetch_row(res1)) != NULL){ //Tarkistetaan pitääkö tapahtumaa vielä suorittaa intbuffer = atoi(row1[0]); if(intbuffer > aika) break; //Tarkistetaan tapahtuman tyyppi if(row1[2] == EVENT_S_BUILD){ //Rakennus } else if(row1[2] == EVENT_S_DEMOLISH){ //Purku } else if(row1[2] == EVENT_S_REINFORCE){ //Vahvistus } else if(row1[2] == EVENT_S_ATTACK_NORMAL){ //Normaali hyökkäys } else if(row1[2] == EVENT_S_ATTACK_SCOUT){ //Tiedustelu } else if(row1[2] == EVENT_S_SEND_RESOURCES){ //Resurssilähetys } else if(row1[2] == EVENT_S_TRAIN){ //Koulutukset } else if(row1[2] == EVENT_S_DEVELOPE){ //Kehitykset } else if(row1[2] == EVENT_S_EMPTY){ //Tyhjä tapahtuma } else{ sprintf(buffer, "Not able to identify event type: %s", row1[2]); logError(buffer); } } //quit = 1; }
SELECT MIN(aika) tapahtumatukoksen varalta; ensin suoritetaan ne joiden olisi pitänyt valmistua pisin aika sitten.
Tapahtumatietokannan muoto, kieli PHP:
mysql_query("CREATE TABLE events (aika INT(10), id INT(10), tyyppi INT(2), pelaaja INT(8), kyla INT(8), data1 INT(10), data2 INT(10), data3 INT(10), data4 INT(10), data5 INT(10), data6 INT(10), data7 INT(10), data8 INT(10), data9 INT(10), data10 INT(10), data11 INT(10), data12 INT(10), data13 INT(10), data14 INT(10), data15 INT(10), data16 INT(10), data17 INT(10), data18 INT(10), data19 INT(10), data20 INT(10), data21 INT(10), data22 INT(10), data23 INT(10), data24 INT(10), data25 INT(10), data26 INT(10), data27 INT(10), data28 INT(10), data29 INT(10), data30 INT(10));", $yhteys);
Jos tapahtumat suoritetaan vasta kun joku käyttäjä tekee jotain, ongelmia tuli ainakin itselleni resurssituotantojen laskemisessa (koska paras tapahan on merkitä muistiin tuotannot, resurssit ja viimeisin päivitysaika, mutta hyökkäys tai muu tapahtuma voi muuttaa tuotantoja tai varastojen sisältöä, ja jos tapahtumaa ei suoriteta reaaliajassa, käyttäjällä voi olla väärä määrä resursseja).
Helpoimmalla selviät, kun tapahtumat suorittaa erillinen ohjelma reaaliajassa. Suurella käyttäjämäärällä myös lagaaminen estetään, sillä C(++) on nopeampaa kuin PHP.
Aihe on jo aika vanha, joten et voi enää vastata siihen.