Fengist's Forum Posts

  • Ok, I've just had an epiphany. I've been contemplating a chat system for my latest project. The options I had up until a few moments ago were:

    Long polling - whereby the game client sends an AJAX request every second or so to see if there are any new chats it needs to grab. While this system definitely works, I can see it turning a web server into a puddle of goo when you have 1000 clients polling for chats every second along with trying to serve up web pages and responding to other AJAX requests.

    Websockets - whereby I write some websocket server in node.js or c# and have it run as an application on a server somewhere with the game client logged into it. While this would be duplex, instantaneous and efficient, trying to configure a wss server and write the code for it sounds like a nightmare. Not to mention the fact that it would pretty much required a dedicated server somewhere so that it could run continuously.

    And then my epiphany:

    Server-Sent events - I just read about these here:

    https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

    and decided to test it out and ummmm... wow.

    So, I dropped an HTMLElement plugin on my layout and put this in the text field:

    <ul><div id="screen"></div></ul>
    

    I then took my js file with all my bits of code and added this (with the url pointed to the php on my web server)

    var evtSource = new EventSource("//api.example.com/ssedemo.php", { withCredentials: true } ); 
    
    evtSource.onmessage = function(e) {
     var newElement = document.createElement("li");
     var eventList = document.getElementById('screen');
    
     newElement.innerHTML = "message: " + e.data;
     eventList.appendChild(newElement);
    }
    
     evtSource.addEventListener("ping", function(e) {
     var newElement = document.createElement("li");
     var eventList = document.getElementById('screen');
     
     var obj = JSON.parse(e.data);
     newElement.innerHTML = "ping at " + obj.time;
     eventList.appendChild(newElement);
    }, false);
    

    I took the php code from the URL above, added in a CORS header, which is really nice because I can pretty much guarantee that it'll be coming from the game, and ran my project.

    To my amazement, I started receiving messages from the php script.

    message: This is a message at time 2019-05-29T13:46:09-0400

    ping at 2019-05-29T13:46:10-0400

    ping at 2019-05-29T13:46:11-0400

    ping at 2019-05-29T13:46:12-0400

    ping at 2019-05-29T13:46:13-0400

    ping at 2019-05-29T13:46:14-0400

    ping at 2019-05-29T13:46:15-0400

    ping at 2019-05-29T13:46:16-0400

    message: This is a message at time 2019-05-29T13:46:16-0400

    ping at 2019-05-29T13:46:17-0400

    ping at 2019-05-29T13:46:18-0400

    ping at 2019-05-29T13:46:19-0400

    ping at 2019-05-29T13:46:20-0400

    Now normally, web hosts force php scrips to crash and burn after a set time. This one, 30 minutes later, is still sending pings to my C3 game client. So, either my host has lost their mind or,

    The only downside 2 downsides I can find to this so far is that:

    • It doesn't work in Edge and IE browsers (which I can certainly live with since IE is dead and Edge is switching to Chromium).
    • It's not duplex, it's a one way communication from the server to the client. BUT - Ajax requests to send in chats from the client and server-sent events to feed out the chats should work.
    • When running the php script above on Apache it opens a new process for every single client that connects. You get 1000 clients and you turned your server into goo again. A huge drawback.

    Now, according to this post:

    https://stackoverflow.com/questions/14225501/server-sent-events-costs-at-server-side

    Node.js should be able to handle server-sent events with just one process and have thousands of clients connected.

    Anyone else played with server-sent events? Any thoughts?

  • I guess it depends on how you want to term it.

    Games like Rust use Unity as the engine behind their game.

    Games like Eve Online, which is created primarily in Python, the game is the engine.

    To coders, it's semantics...

    To the public though, it's public perceptions and thus, marketing. When the word engine appears, people think of that thing under the hood of their car that makes it go. To most, it's a mysterious, mechanical marvel that they can stare at in wonder and admire, but don't have to think too much about. Calling the code behind a game an 'engine' imparts that same mystery.

    It's the same exact reason that the food industry wants to change 'high-fructose corn syrup' into 'corn sugar': public perceptions and thus, marketing.

  • Not really. You could try to encrypt the local variable and that would deter most people. The problem there is, any password you use to encrypt and decrypt it would be located somewhere in the code. Anyone dedicated enough would eventually find a way to decrypt it. (Trust me, I've had keygens made for software I've written).

    I'm doing something very similar to what you are. I have skills that require x amount of time before they can be trained. What I do is send an AJAX request to a PHP file when they choose a skill to train. When it gets that request it stores that timestamp in a MySQL database. When the user logs in, it sends an AJAX request to retrieve that timestamp. It compares it to the current timestamp and if enough time has elapsed, it sends another AJAX request to update their skills. If the time hasn't elapsed, I have a 1 sec timer on a global event sheet that keeps checking to see if that time has elapsed.

    But, you even have to take other things into account. What if they change the clock on their computer to be say, a week in the future? You'd need some way to validate the current time.

    If people want to hack your game, they will. All you can do is make it as difficult as possible. My solution isn't perfect but, storing things like that remotely on a server is about the best you can hope for.

  • So this is just a thought running around in my head, bear with me.

    Along with Construct, I code professionally in PHP (yep, people actually pay me to write code, amazing). Of late many of the questions I've been answering on the forums either have a direct relation to AJAX and JSON or could be solved with AJAX and JSON. Right now, the solution for Construct programmers is to write their own code to handle these problems or learn the rigors of Firebase. The problem is, most people who write code for Construct have little or no knowledge of other languages.

    So this got me to thinking.

    If there were a service available that would allow you to do the following, would it be of interest?

    Using AJAX, create user accounts and store information like:

    • User name
    • Password
    • Email
    • Date Created
    • Number of logins
    • Last login
    • IP Address

    Email validation.

    • Send the user an e-mail when they create an account with a link that they can click on (or an in-game form) to verify their e-mail.

    Validate user logins:

    • Using AJAX, send a username and password and have it return whether the account is valid or not.

    Store and retrieve various variables:

    • The ability to send AJAX requests that store variables and retrieve them on demand, like high score, timestamps, current level, etc.

    Essentially, it would work like this:

    You send an AJAX request to a server. For example, to check if a user can login you'd send:

    AJAX url : http://www.constructusermanager.com?name=username&password=password&apikey=somehashedkey

    and it sends you an JSON in return.

    {

    "valid": true

    }

    Take note, this would be a HUGE undertaking on my part. While I envision allowing a free account where you could test say 5 users maximum, anything beyond that would require a monthly fee.

    And this is just me thinking out loud. Nothing written in stone...

    What are your thoughts?

  • Browser.ExecJS("Date.now()") will give you the number of milliseconds between 1/1/1970 and now. You can put that number into local storage whenever you wish. When the user starts the game the next time, you can get that number again and subtract the stored value from the current value and know exactly how many milliseconds has elapsed since you stored that number.

    Browser.ExecJS("Date.now()") - stored value = milliseconds elapsed.

    One thing to take note of. Storing variables in local storage is not secure in any way. It's entirely possible, and not that difficult, for a user to go in and edit those variables manually.

  • Then he's not missing anything. What he wants is exactly what I described in the Delphi panels. If you drop a button on a panel in Delphi and you anchor the button to the bottom right of that panel, regardless of how that panel changes in size, the button will always maintain the same x and y position relative to the bottom right of the panel. Once the alignment of the panel and the anchoring of the components is set, you never have to screw with it again.

    There is nothing in Construct whereby I can layout objects and have them maintain their relative position to... well anything. Even pin has it's issues. I can't pin a button to the layout and have it stay in that spot. Instead, I'm forced to create a function that I have to call every time a layout starts or the browser resizes and I have to go through every single visible object on the layout and tell it exactly where I want it positioned and if I want it resized, relative to the viewport dimensions.

    For example. In the project I'm working on I have a sprite in the top right corner of the layout. I ALWAYS want it 10px from the top and 10px from the right, regardless of how the browser is sized. With a Delphi panel, I set it's anchors to top and right and place it... done. In Construct I have to tell it... no, no, I want you HERE... now DON'T MOVE.

  • Ok, I was just curious as to whether there might be characters in there that might affect the sql. Seems not.

    Well, I'm out of ideas. All I can tell you now is that the code is working. It's either your SQL that's not right or your database isn't right.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads

    Thanks for the update guys. As I've mentioned numerous times I'm a horrible JS hack so I'm rarely aware of the developments it undergoes. Nice to know you guys are already well into that ball-game. Google fed me that news this morning and I thot, humm... never heard of that before. Might be something new. Guess not. The way it sounds now, it was just a big publicity stunt for ebay.

    One of the biggest problems with web-based applications is speed. Languages like PHP are compiled by the server each time they're called (yes, the compiled bytecode is cached for speed). JS is compiled by the browser on the end user's computer each time they're called (which I assume is also cached).

    But imagine if you could compile your Construct app into an executable with assembly-like speed.

    https://www.techrepublic.com/article/replacing-javascript-with-webassembly-how-ebay-made-a-web-app-50x-faster-by-switching-programming-languages/

    This may be a long way off yet but...

  • What's the exact user name you're looking for?

  • Over the years I've worked with a lot of IDE's. One of the best is Delphi. It's called a RAD (Rapid Application Development) platform. One of the ways it makes things really easy to work with is something called panels. You can drop these panels on a form (layout) and give them various alignments, like top, left, bottom, center or even custom alignments. When you drop components (objects) onto them, they have anchors and they anchor themselves to the panels. You can set the anchors to any combination of top, bottom, left or right. The beauty of this is, as the form gets resized, the panels automatically resize based on their alignment and the components anchored to them stay in a position relative to their anchor setting. A top alignment will adjust it's width but not it's height, to match the form size. Left aligns, adjust height, but not width. Panels and anchors are an almost fool-proof way of developing aps and having all of the components stay exactly where you want them, regardless of the size of the form.

    That... is something I desperately miss in C3. Call them containers or what you wish, C3's methods for layout placement always forces me to manually place things exactly where I want them in the onStart and browser resize events. And to me, that's pretty clunky.

  • As for price there's two ways to do it.

    1. You make a FANTASTIC plugin that saves users TONS of time or gives them features they can't get anywhere else and charge a lot for it or.

    2. Bubblegum. You make a lot of simple plugins that make life easy and charge a little for each one.

  • It depends. Can the buttons be fully customized with CSS? Can the tooltips be customized with CSS? Can I change the fill and colors of the checkboxes and radio buttons? Are there onHover events and can I change the CSS when the hover event fires?

    Basically, as someone experienced in HTML and CSS can I make them look exactly the way I want, when I want but still make them look good when I don't want to mess with CSS?

    Can you make both noobs and pro's happy?

  • the error now returns:

    No user found with that name.

    That's perfect!

    That means that the username you searched for wasn't in the database. That's good because it means there were no errors. You connected to the database, you performed a query but it returned 0 results.

    Now, all you have to do is add a user to the database and search for them.

    Binding params is relatively new to php. It's purpose is to prevent things like SQL injection when getting query strings like $_GET. Basically, the way it works is this.

    In your query you substitute the ? for the insecure variables you want to put in the query.

    You then prepare the query. Then you bind the variables to the query. In the bind_param the 's' simply tells the bind command that you're passing a string and it substitutes the first ? (which it now knows is a string) for the $_GET["name"]. If you have say 3 ?'s in your query:

    SELECT id from user where username = ? and birthday = ? and country = ?

    $stmt->bind_param("sss", $_GET["username"], $_GET["birthday"], $_GET["country"])

    Then, you execute the query and finally get the results.

    Very glad you got it working!

  • Ok, I'm wholly unfamiliar with PDO and how it connects but the error you're getting is because it's failing to make a connection to the database so we need to do some error checking. I'm making a guess that you're using MySQL so let's try establishing a mysql connection instead:

    You currently have the PDO password set to '' which means, you aren't using one. I have yet to see an install of MySQL that allows no password on the root account unless you specifically set it to none.

    In the script below, you're going to need to replace DB_PASSWORD with the password you used when you set up the root account and put it inside single quotes like this:

    'password'

    If you're sure you don't have a password for that database then replace DB_PASSWORD with:

    ''

    Hopefully, this will work. Just run this from the browser. Once it does work, you can add in the:

    header('Access-Control-Allow-Origin: *');

    Back at the top.

    Take note, this produces a string as the AJAX result. From what I saw you had the result set to a number. If this does work, you will need to change it to see the errors.

    <?php
    $base = new mysqli('localhost', 'root', DB_PASSWORD, 'stockage');
    // Check connection
    if ($base->connect_errno) {
     die("Failed to connect to MySQL: " . $base->connect_error);
    }
    
    $sql = "SELECT id FROM user where username = ?";
    
    if (!$stmt = $base->prepare($sql))
    {
     echo "Prepare failed: (" . $stmt->errno . ") " . $stmt->error;
    }
    if (!$stmt->bind_param("s", $_GET['name'])){
     echo "Bind failed: (" . $stmt->errno . ") " . $stmt->error; 
    }
    if (!$stmt->execute()){
     echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error; 
    }
    if (!$result = $stmt->get_result()) {
     echo "Get result failed: (" . $stmt->errno . ") " . $stmt->error; 
    }
    if ($result->num_rows > 0) { 
     $row = $result->fetch_object();
     echo $row->id;
    }
    else
    {
     echo 'No user found with that name';
    }
    ?>