Praxisnähe von JavaScript, u.a. für Spieleentwicklung

(Hinweis: Das hier ist aus dem „Frust-Thread“ abgetrennt, wo ich zuerst eine (frustrierende!) Beobachtung im Zusammenhang mit JavaScript leicht zynisch als „Quiz“ gepostet hatte, und woraus sich dann eine kurze Unterhaltung über die Eignung von JavaScript für bestimmte Programmieraufgaben ergeben hat…)


JavaScript-Quiz:

const buffer = ...;
console.log(buffer.length); // Ausgabe: 2149425

const array = new Int8Array(buffer, 0, 4);
console.log(array.length); // Ausgabe: ???

Was wird in der letzten Zeile ausgegeben?

(Und, damit ich da auch einen Nutzen draus ziehen kann: Warum, zur Hölle, und wie kann man das verhindern? *kopfschüttel* )

Die erste Zeile wird zumindest bei mir im FF mit einem Syntax Error quittiert.
„expected expression, got ‚…‘“
Darum die Frage: Gehören die drei Punkte dahin, oder steht da normalerweise etwas Anderes?

Da steht „irgendwas“, wo ein Buffer herkommt, der eine Länge von 2149425 hat…

Okay, das dachte ich mir schon. Ist buffer ein Array oder ein ArrayBuffer? Das scheint hier nämlich einen riesen Unterschied zu machen, denn wenn man ein ArrayBuffer dieser Länge anlegt, dass ist buffer.length undefined und array.length 4, wie man es vermutlich erwartet. Ist buffer hingegen ein Array, ist die Ausgabe beide Male 2149425.

Tja. Wer weiß das schon? Die Ausgabe bei

console.log(buffer);
console.log(typeof buffer);

ist

<Buffer 62 33 64 6d 01 00 00  ... >
object

(Normalerwiese denke ich mir bei Variablennamen ja etwas, aber … es ist schwierig, ganz offensichtlich…)

Die Frage, ob es ein „Array“ oder ein „ArrayBuffer“ ist, kann ich also beantworten: Es ist ein Objekt!
(Vielleicht ein „Buffer“…).

In jedem Fall wird es schwierig, zu begründen, warum die Länge beide Male die gleiche ist, und (zumindest mir gegenüber) unmöglich, das zu rechtfertigen: Das haben sie einfach gnadenlos verbockt :face_with_symbols_over_mouth: *kopfschüttel*

(Hab’s jetzt mit const array = new Int8Array(buffer).subarray(0, 4); und einem Hasskommentar gelöst, aber das ist eber Nebensache…)

EDIT: Noch mehr Nebensachen: Es ist wohl ein Buffer, und das ist ein Uint8Array, zumindest seit Version 3. Eigentlich brauche ich ja eine DataView, und die braucht einen ArrayBuffer, aber zum Glück enthält Buffer ein field namens buffer, und das ist ein ArrayBuffer.


.

Mir ist sowieso nicht klar warum man JS nicht sterben lässt und eine moderne ScriptSprache einführt anstatt aus ein Frankenstein-Monster zu bauen.

Naja gut. Ein wenig Hoffnung kann man ja mit wasm haben. Bietet zwar keine Möglichkeit zu scripten (was leider manchmal gerade im Browser doch sehr nützlich sein kann) - aber wenigstens für Anwendungen wird JS hoffentlich irgendwann nicht mehr wichtig sein.

Weil man dann jedem, der es geschafft hat, seine Applets in JS zu konvertieren, zumuten müsste, seine Seiten erneut auf etwas umzustellen, was er „from scratch“ neu lernen müsste.
Für welche Anwendungen, wenn nicht Browser-Anwendungen, sollte JS denn noch nützlich sein? Sag bloß, da beut noch Einer was Anderes mit?

Da man JS nicht von heute auf morgen sterben lassen kann, wäre da mehr als genug Zeit für einen Übergang.

JS ist doch die Eierlegende Wollmilchsau. Mit Node.js kannst du Backends schreiben, mit Electron Desktopanwendungen und so Zeug wie react-native kommst kommt da auch eine mobile app raus. Nicht zu vergessen so manche Game-Engine setzt auf JS.

Hmm… keine, die ich kenne. In denen, die ich kenne, ist LUA vorherrschend und Bethesda hat gar eine eigene Script-Engine (Stand Skyrim).

Und soweit ich weiß, versucht man mit Java-Script gerade so Dinge wie Pyton und LUA gewaltig auszustechen und die Frage ist, ob es was bringt und das nicht nur für Script-Kiddies

Das mit den Engines bezog sich vermutlich/vielleicht auf sowas wie https://threejs.org/ und https://www.babylonjs.com/ (das sind die „big player“ - eine nicht explizite „Liste“ weiterer findet man z.B. über https://github.com/cx20/gltf-test ). Falls das hier aber zu einem eigenen Thread wird, könnte das abgespalten (oder gleich an "The JavaScript phenomenon is a mass psychosis" angehängt) werden :wink:

Es wird ja versucht, über JS Sachen „drüberzustülpen“ - im speziellen ja TypeScript. Aber selbst im besten Fall muss man antizipieren: Sooo schnell wird man JS nicht los.

In Elder Scrolls Online ist auch Lua die Scriptsprache.

Final Fantasy 14 hat leider gar keine Benutzererweiterungen, daher auch keine Script-Sprache am Start.

Ein Spiel mit JavaScript als Scriptsprache fände ich zunächst mal recht… nun ich würde es skeptisch beäugen.

Ich fänd’s toll, denn dann müsste ich mich überhaupt nicht mehr mit LUA befassen. Aber ich denke, die Mehrheit hier weiß schon, warum es in Spielen und schon gar nicht in Online-Spielen verwendet wird… z.B. weil man Schnittstellen hat, mit denen man recht einfach mit Programmen außerhalb der Umgebung (z.B. ESO) kommunizieren kann - also an der Umgebung vorbei, was Potenzial zum cheaten bietet. Wenn ich mir ansehe, wie umständlich das beim Tamriel Trade Center aus ESO gelöst ist, dann würde ich sagen, mit LUA geht es nicht so einfach.

@Marco13: Was Typescript angeht… Irgendwie habe ich das Gefühl, dass auch das bald überflüssig wird. Wenn ich mir ECMA 6 so ansehe… da fehlt doch nur noch die Typsicherheit?

Vielleicht interpretiere ich einige Statements hier nicht richtig. Ich kenne mich weder mit Spielen noch mit Scriptsprachen wirklich aus. Aber es klingt, als wäre es wichtig, zu unterscheiden, zwischen einer Scriptsprache, mit der man ein Spiel „konfiguriert“, und der Engine an sich. Ganz grob um den Unterschied zwischen

var enemy = loadResource("enemy.gltf"); 
moveAlongPath(enemy, myPath);
...

und

glUniform3fv(directionLocation, 1, lightDirection);
glUniform4fv(ambientColorLocation, 1, ambientColor);
...

Ich habe einige meiner ersten Schritte in C-Programmierung übrigens mit https://de.wikipedia.org/wiki/QuakeC gemacht :sunglasses:

Ich meine, vorher war das Spiel ja voll unrealistisch: Wenn man mit der Double-Shotgun und Quad-Damage einen Rottweiler zerschossen hat, ist der in genauso viele Brocken zerplatzt, wie ein Shambler. Da hab’ ich für den Shambler einfach die throwGib-Funktion per Copy+Paste ca. 20 mal eingefügt :smiley: )

*einen Schluck aus einem Wasserglas nimmt*
*was von „nur noch die Typsicherheit“ liest*
*das Wasser prustend über den Tisch spuckt* :smiley:

"Nur" noch die Typsicherheit?!? Das ist doch (mit) das wichtigste. Im Moment ist JavaScript einfach nur eine „Sprache“, mit der man Maps füllen und auslesen kann. Mehr nicht.

var someObject = {
    name: "Foo",
    age: 12
}

someObject.age = "Not a Number";
someObject.mane = "The result of a typo";
someObject.value = 0;
if (!someObject.value) {
    console.log("Value is undefined or null or 0 or the empty string, who cares...");
}

Ich find das grauslig.

Aber das kann jeder sehen, wie man will

Ich denke mal, dass wenn eine Game-Engine mit einer Scriptsprache geschrieben wurde, sie sich um den Part, wie man sie über eine Script-Engine modifizieren oder konfigurieren kann, nicht mahr allzu viele Gedanken machen muss - aber klar… unterscheiden muss man da schon. Ich aber würde mir schon Gedanken machen, wenn einer auf die Idee kommt, eine Engine in Javascript zu schreiben und meint damit anspruchsvolle Desktop-Spiele kreieren zu können.

Ich sehe das so, dass Typsicherheit Vor- und Nachteile hat und beides hat damit zu tun, auf was man in seinem eigenen Code alles beachtet und was nicht. In Javascript-Funktionen kann man nämlich wunderbar auf gültige (also in der Funktion verwertbare) Argumente testen - also Dinge, an die man nicht denkt, wenn Typsicherheit gegeben ist, wobei man sich stattdessen dann mit Typecasts (insbesondere bei Generics) rumärgern darf. Mehr oder weniger grauslig ist Beides - man muss damit klar kommen.

Aber davon mal ab… so etwas wie „if(someobject.value) {…“ würde ich in Javascript schon gar nicht mehr schreiben.

(BTW: Ich werd’ das hier bei Gelegenheit mal abschneiden, so ab Frust-Thread vielleicht, und in einen eigenen Thread packen - nicht mehr heute, vermutlich)

Man muss sich schon Gedanken machen, nämlich wo die „Trennlinie“ zwischen „Kern“ und „Script-Schicht“ verläuft. Und vielleicht ist das gerade dann besonders schwierig, wenn beides in der gleichen Sprache geschrieben ist. Dass man dann vielleicht auch einfach

const myPlugin = (engine) => {
    engine.core.privateParts.players["myName"].health = 1000000000;

    engine.core.privateParts.players["myName"].die = function() {
        engine.core.privateParts.players["opponent"].die();
    };

}

schreiben kann kommt noch oben drauf (wo wir gerade beim anderweitigen JavaScript-Bashing sind :smiley: )

Das Problem mit der „ungetyptheit“ ist so gesehen nicht so klar abzugrenzen. Mir ist fast egal, ob eine Variable den „Type“ var hat und sowohl eine Number als auch ein String sein kann. Wenn man das systematisch, nachvollziehbar und gewissenhaft umsetzt, kann das OK sein. Dass es, wenn man es komplett und von Grund auf gegen die Wand fährt zu sowas wie dem https://eqeq.js.org/ führt, ist ein anderer Punkt. Aber was ich eben grauslig finde ist, dass man sowas wie das oben angedeutete foo.bar.someFunction = doSomethingElse machen kann, und dass ähnliche Dinge teilweise als „normal“ angesehen zu werden scheinen.

Noch ein kleiner Nachtrag zum letzten Beitrag: Ich bin heute über genau das gestolpert, was ich im letzten Beitrag so planlos und als einen meiner üblichen Kassandra-Rufe skizziert hatte. Zumindest ist, soweit ich https://www.npmjs.com/advisories/1523 verstehe, genau das: Irgendjemand kann irgendwo irgendeinem „Ding“ eine Funktion unterjubeln, die etwas böses macht.

Schön, dass das einen Namen hat: „Prototype Pollution“.
Toll.
Workaround? Ganz klar: „Nimm doch einfach irgendwas anderes ¯\(ツ)/¯“. Ja, Leute, toll. Das Ding hängt als transitive dependency der Tiefe 3 oder 4 in den elementarsten Standard-packages, die man sich nur vorstellen kann. So ein riesen Haufen Mist. Das ist wirklich unglaublich.

1 Like