Jump to content


Popular Content

Showing content with the highest reputation since 12/18/2018 in all areas

  1. 5 points

    My SMS Project: Paintball Net Revival

    Back in the mid-90's, my brother created what he called an "action MUD". He called it "Paintball Net". PBN used ANSI text terminal commands to create a combined roll-and-scroll and animated text experience. ! (exclamation points) were trees, _ (underscores) were grass, ^ (up carets) were mountains, and more. Your "avatar" was a "Y" (uppercase y) and enemies were * (asterisks). You used MUD-like commands to move around the world and target your paintball gun and buy and sell and more. I wish I had a screenshot of what the first version looked like, but you'll just have to imagine. 😃 He asked me to create the GUI for the game. That was 1996, and I had just purchased Delphi 2 and wrapped up my first "learn Delphi" project. This sounded like a good next step, and "PBTerm" was born. I *do* have screenshots of that. Oh, yeah. Love those 16-color Windows graphics. 😃 During the years it was online, the game evolved and upgraded to look more like this: We were never going to win any awards, but we had a very devoted player community. 😃 Paintball Net was online from the summer of 1996 through the summer of 2000, when we took it offline to focus on other projects. The game was never huge, but we had thousands of players come through over that period. And since then, every year at least a few of the players have reached out and asked/begged/pleaded/demanded if we were going to put it back online. There really wasn't much chance of the original version going back online. The original server, written in ANSI C for Linux had proven rather fragile, and was a big part of why we took the game offline. It was taking hours every day just to keep it up and running, in addition to time spent managing the community of players. On top of that, a hard drive incident in 2008 had cost me the source code of a number of core third-party/modified components for PBTerm. This past summer, though, I realized I might be able to make the game live again using Smart Mobile Studio. I would do a straight port of the ANSI C server to Smart Pascal using Node.JS and WebSocket, and I would rebuild the PBTerm client as a browser-based client. I'm not going to say it was *easy*, but it has been a lot of fun. ANSI C converts to Pascal without a lot of painful gyrations. And Node.JS seems a LOT more flexible, stable, and powerful than the TCP sockets approach we were using before. Also, game development is a lot easier when you already own all the graphic and audio resources. 😃 This is the server "in action"... Recreating the client has been more complicated. 20+ years of Delphi habits had to be adapted to the new reality of SMS and a browser-based UI. But that's coming together too. It might be obvious, but I'm not targeting this game at mobile. Paintball Net needed a mouse and keyboard in 1996, it's gonna need a mouse and keyboard in 2018. Also, I've made as few modifications to the gameplay as possible. I really wanted to bring back the original as much as I could. Today I got the handful of sound effects integrated, which was easier than I expected. I'm planning to start testing soon. I just need to line up a server to use and find a few volunteers. I'm excited. This would never have happened without Smart Mobile Studio. So I figured I would share. Merry Xmas! -David
  2. 3 points

    inter-tab processing

    Would it be possible to implement a 'client-server' architecture where both the client and the server are executed locally (but in separate spaces). Or just divide an app up in different parts where each part is executed in its own environment and communicates with the other parts as necessary. And all this pure locally. The answer is yes: use separate browser tabs. Surprisingly there are multiple ways of doing this, and the candidate technologies enabling inter-tab communication are : local storage (really) shared web workers broadcast channelling webrtc The demo in this post is based on using localStorage and consists of two separate but standard Smart projects, dubbed 'server' and 'client'. The server-project is just a form with an embedded anchor html element (<a>). When clicked the href-attribute is set to the output of the client-project ('client.html') and the target-attribute to '_blank'. This has the effect of opening up a new browser-tab which runs the client-project. So now there are two browser tabs open, each running its own project. Communication between these tabs is possible using localStorage : mutations in localStorage generate storage-events and these events can be captured and used for communication purposes. This url (https://www.lynkfs.com/Experiments/webrtc/localstorage/server.html) opens up both tabs at once (you might have to allow pop-ups in Chrome or FireFox), and mimics a login process. Server-code and Client-code (native framework but you'll get the idea) Login form : button.OnClick := procedure(sender:TObject) begin //this sends 2 events to the server, which can then validate name and password window.localStorage.setItem('name',name.handle.value); window.localStorage.setItem('pw', pw.handle.value); end; window.onstorage := procedure(e:variant) begin //after validation the server sends a new event with the results console.log(e.key); console.log(e.oldValue); console.log(e.newValue); footer.SetBounds(100,300,200,30); if (e.key = 'result') and (e.newValue = 'ok') then footer.setInnerHTML('login successful'); end; happy holidays
  3. 3 points

    Smart Mobile Studio 3.0.2 is released!

    Smart Mobile Studio 3.0.2 is released. This version contains all the fixes and improvements from the development-channel. There are lots of bug fixes and improvements to the IDE thanks to all the help from our users here. The Smart Mobile Studio team wants to with everybody a Merry Christmas and Happy New Year. Release notes: https://smartmobilestudio.com/2018/12/21/smart-mobile-studio-3-0-2-released/
  4. 3 points

    Development updates

    New update available: RTL: TW3TabControl: AnimateTabs-property to control how tabs are changed. TW3ListBox: Prevent an exception if TW3Image is used as a line control and OnShowItem is not set. TW3ListMenu, TW3HeaderControl and TW3SimpleLabel: Don't set default caption to classname during initialization. DWScript: Capitalize day and month names correctly (January instead of january, Sunday instead of sunday) IDE: Improvements to the way the IDE reacts to a changed external file. Use caption while drawing generic controls instead of component name.
  5. 2 points

    serviceWorkers (fetch)

    WebWorkers are a way of off-loading tasks from the main browser into a separate thread. ServiceWorkers sit between the browser and the network and extend these capabilities by a couple of powerful features : offline detection and interception possibilities of network requests (fetch api) resource caching under program control (new cacheStorage api) background syncing saving browser apps as icons on the homescreen serving push notifications ServiceWorkers are integral to Progressive Web Apps Architecturally a serviceWorker is just a separate js file, which means that 2 Smart projects are needed (one for the main program, one for the serviceWorker). For normal webWorkers there is a workaround in that it is possible to generate an in-memory js-file using the blob: protocol (see forum post here), so the webWorker can be generated from the main program. For serviceWorkers this approach should work as well, however all modern browsers have closed this avenue (see here, here and here). Not sure if this is temporary or permanent. ServiceWorkers are created in the main program, a bit differently then normal. No 'new' object constructor but instead a call to a registration function, returning a promise. var navigator external 'navigator': variant; if navigator.serviceWorker then begin navigator.serviceWorker.register('sw-v1.js') .then(procedure(registration:variant) begin console.log('Service Worker registered with scope: ', registration.scope); end) .catch(procedure(err:variant) begin console.log('Service worker registration failed: ', err); end) end; (Adding the link to the external navigator object in the first line means no asm blocks are required. The above could be wrapped up in a TServiceWorker object). 1) network request interceptions (fetch) For the serviceworker : start a new project and delete all pre-generated forms and units. Set output to js file (linker) and unclick 'use main body' in code generation. Replace contents of root-unit with var sw : variant; asm @sw = self; end; sw.addEventListener("fetch", procedure(event:variant) begin if (event.request.url.includes("res/app.css")) then begin event.respondWith( fetch("res/appmodified.css"); ) ); end end); Soon as the request to load the standard Smart resource-file 'res/app.css' is detected, it is intercepted and replaced with another resourcefile. Usually communication between worker and main is done through messaging. There is however a short-cut where the worker can modify the calling main page directly : add a Response object to the event.responseWith method with appropriate headers asm event.respondWith( new Response( "body {background: green !important;}", {headers: {"Content-Type": "text/css" }} ) ); end; this will change the backgroundcolor of the form to green. Change the Content-Type to "text/html" and the preceding string to valid html and the form will be replaced with the rendered html content. demo (click button and do refresh) and projects (main and worker)
  6. 2 points
    Here is an example: else if ((aPlayer.TeamNum = 1) and (((team[0] = 0) and (team[1] <> 0)) or (((team[1] <> 0) or (team[0] = 0)) and (Game.Team1Splats < Game.Team2Splats)))) or ((aPlayer.TeamNum = 2) and (((team[1] = 0) and (team[0] <> 0)) or (((team[0] <> 0) or (team[1] = 0)) and (Game.Team2Splats < Game.Team1Splats)))) then Clicking on the opening parenthesis of a "block" correctly highlights the closing parenthesis. The reverse isn't true. Clicking on the closing parenthesis (for example, the one before the "then") highlights about halfway back to the opening. After spotting this a few times, I figured I'd report it. ? -David
  7. 2 points

    mORMot with SMS

    Having read the posts in this thread, I'm warming to using mORMot. Looking for a working project and a bit of explanatory text
  8. 2 points

    Send an email ?

    a "smarted" up example of sending gmails using the gmail client library (replaces html file of option 2a previous post) a form with 3 buttons (button1 : log in / button2: log out / button3 : send gmail) .... var document external 'document': variant; var console external 'console': variant; var gapi external 'gapi': variant; implementation { TForm1 } procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components var Script := document.createElement('script'); Script.src := 'https://apis.google.com/js/api.js'; Script.setAttribute('async',''); Script.setAttribute('defer',''); document.head.appendChild(Script); Script.onload := procedure begin // Load the API client and auth2 library gapi.load('client:auth2', procedure begin gapi.client.init(class apiKey = '********2qOeiRlg2humU4YifLyNqt2TrWR2kGk'; discoveryDocs = ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"]; clientId = '********7354-7kp9br0phbsdfkcsilu660u7uq9p6tqs.apps.googleusercontent.com'; scope = 'https://www.googleapis.com/auth/gmail.send'; end); end); end; end; procedure TForm1.W3Button1Click(Sender: TObject); //log in begin gapi.auth2.getAuthInstance().signIn(); end; procedure TForm1.W3Button2Click(Sender: TObject); //log out begin gapi.auth2.getAuthInstance().signOut(); end; procedure TForm1.W3Button3Click(Sender: TObject); // send gmail begin // asm const message = "From: from@gmail.com\r\n" + "To: to@hotmail.com\r\n" + "Subject: Subject of your email\r\n\r\n" + "with body of text here, separated by a blank line"; // The body needs to be base64url encoded. const encodedMessage = btoa(message); //replace all + with -, replace all / with _, and remove the trailing = to make it URL-safe //const reallyEncodedMessage = encodedMessage.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') //problem : Smart compiler can't handle \ characters gapi.client.gmail.users.messages.send({ userId: 'me', resource: { raw: encodedMessage //should be : reallyEncodedMessage } }).then(function () { console.log("done")}); end; // end;
  9. 1 point

    Obfuscation Issue with Asm Block

    Oops. I forgot an @. That's why there was an issue. -David
  10. 1 point

    Websockets OR Node?

    No, it can't just be a client app. You need a server app also. You just have to decide, how extensive a server app you want to make. If you have a minimal server app with just the json download/upload, your client app needs to contain all the business logic. If you move the business logic and data manipulation to the server, the client app can be very simple. It just has to display data and ask the server to make changes.
  11. 1 point

    Websockets OR Node?

    Are you looking for a solution for the client app or the server side? Basically, in node you can write a small server that listens to get and post requests. In get, you send the json file the server has and with post you retrieve the changed json file. The client only has to then do simple get/post requests using TW3HttpRequest. However, it's never a good idea to blindly trust the json-file that the client sends. If the client only does small and finite changes to the json, you can pretty easily make your own api for changing the json-file. When you do that, the client sends post requests to the server and the server checks and updates the json based on the parameters in the requests.
  12. 1 point

    Websockets OR Node?

    it depends websockets is but one mechanism for client-server communication. Node supports ws but there are php websocket implementations as well. Node runs on most if not all platforms, but there are alternatives. Ultimately you'll have to make choices re client type (browser web app, native, ...), communication protocol (websocket, ajax/xmlhttp, ...), middleware (if any), server platform (windows, linux, cloud, ...), server language (node/smart/js, delphi, php, aws), back-end database (oracle, mysql, firebase, ...). These choices will be influenced / dictated by the functional requirements of your app (is your json file unique for all users or per user, do updates need to be pushed in real time, ...), scale (concurrent clients), reliability, availability and costs (all servers incur costs, although some providers provide limited free tiers). hny
  13. 1 point

    stable x unstable IDE

    I don't want to interrupt your holidays. I thought I was going crazy. Crazy about smart. I have SMS 2.2.2 (last winXP), SMS 3.0.2 (stable release) and SMS (development) installed. It was exactly the same project, same source, but I forgot to copy the SynCrossPlatform units ( SynCrossPlatformCrypto.pas | SynCrossPlatformREST.pas | SynCrossPlatformSpecific.pas ) into SMS3.0.20/Libraries folder and the issue has vanished, the designer worked as expected in SMS - without any error.
  14. 1 point

    mORMot with SMS

    In fact, there is an bug on older SMS versions 1.2 | 2.0 | 2.0.1 | 2.2 and 2.2.2 - the TObject::Destroy method would just delete the property named "prop" rather than the actually all the properties of the object itself. For instance, obj.Free is doing nothing because the method Destroy was buggy // old SMS version var TObject={ (...) Destroy: function (s) { for (var prop in s) if (s.hasOwnProperty(prop)) delete s.prop }, Destroy$: function(s) { return s.ClassType.Destroy(s) }, (...) } On newer SMS version 3.x, they fixed the TObject::Destroy method.
  15. 1 point


    I was working on a PWA but postponed it until after my servers got upgraded to https (which has now happened). I'll have another look soon
  16. 1 point

    Sound Playback in Built-in/Debugger Browser

    Yes, I noticed the same when I tested all the featured demos. Funny thing is that audio did work in some of them. This will probably improve when we upgrade the embedded chrome in the internal browser.
  17. 1 point

    Programs NOT executing in browsers

    I tried rebooting. That didn't work I fixed it. No sure how, as I did a number of things. Reset IP address. Disabled adapter and renabled, etc. Sees to be working now
  18. 1 point
    Daniel Eiszele

    Forum access

    Have a look at this thread and see if it's the same issue?
  19. 1 point
    Removed, committed to Git and pushed. It will definitely be in the next update.
  20. 1 point
    Daniel Eiszele

    CSS Resource Files

    Thanks for reporting this one @DavidRM, and thanks for fixing it @jarto. I have been having issues with this for a while and didn't take the time to look into it properly. Works as expected in current release version 3.02!
  21. 1 point
    SMS 3.0.2 portable version a) Simple click at https://smartmobilestudio.com/download/3.0.2/setup.exe to install SMS 3.0.2 and install at "C:\smartms" b) move all files and directories from "C:\Users\All Users\The Smart Company\Smart Mobile Studio" to the folder "C:\smartms" c) create a file called "settings.ini" at the directory "C:\smartms" [Settings] Channel=DEVELOPMENT RelativePaths=1
  22. 1 point
    I'm not sure I'm seeing this any more. I just assumed it was fixed. 😃 Or maybe I was wrong in the first place...
  23. 1 point

    TabControl & Tabs ?

    I'll add a property for this.
  24. 1 point

    TabControl & Tabs ?

    @IEliteIt's not a property. You have to make a change to the code. procedure TW3TabControl.SetTabIndex(const Value: integer); begin if not (csDestroying in ComponentState) then begin if (csReady in ComponentState) then begin if FTabs.Count > 0 then begin if FHeaders<>nil then FHeaders.SelectedIndex := Value; var CRect := FContentBottom.ClientRect; if FPreferredTabIndex = Value then begin FPreferredTabIndex := -1; FTabIndex := Value; FScrollController.ScrollTo(-Value * CRect.Width, 0); SendTabEvents(Value); end else // drm - no scrolling // FScrollController.MomentumScrollTo(-Value * CRect.Width, 0); begin FTabIndex := Value; FScrollController.ScrollTo(-Value * CRect.Width, 0); SendTabEvents(Value); end; // --- end; end else FPreferredTabIndex := Value; end; end;
  25. 1 point
    If this will help you, here is a demo project (attached) where I created my own ListBox item (Image (left-aligned) and Label (client-aligned)) Listbox3.zip