Git Product home page Git Product logo

regoth-bs's People

Contributors

ataulien avatar charlydelta avatar ghtyrant avatar gigagrunch avatar kirmesbude avatar mbdev87 avatar mworchel avatar nikomoravec avatar zayuim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

regoth-bs's Issues

Missing dependencies for Ubuntu 18.04

Following the official Wiki article on the clean Ubuntu 18.04.3 led me to 2 errors while building the project.

CMake Error at lib/bsf/Source/CMake/Modules/FindLibUUID.cmake:22 (message):
  Cannot find LibUUID.
Call Stack (most recent call first):
  lib/bsf/Source/Foundation/CMakeLists.txt:24 (find_package)


-- Configuring incomplete, errors occurred!
CMake Error at lib/bsf/Source/Foundation/CMakeLists.txt:32 (message):
  Could not find XRandR library.


-- Configuring incomplete, errors occurred!

The solution is to install two additional packages:

  • uuid-dev,
  • xrandr-dev.

For some reason, xrandr-dev wasn't available for standalone installation with default official repositories, but installing xorg-dev resolved that issue: xrandr-dev was installed as dependency for xorg-dev.

I believe this should be mentioned on the system packages Wiki section.

Render Sky Plane

In Gothic 1, the sky is rendered as a plane. This has been implemented in REGoth before, so the old implementation can serve as a reference:

https://github.com/REGoth-project/REGoth/blob/master/src/render/SkyRendering.cpp

In the new implementation, I suggest creating a component which takes care of rendering the sky. A plane-mesh is available inside bsf and can be retrieved like this:

  bs::HMesh planeMesh = bs::gBuiltinResources().getMesh(bs::BuiltinMesh::Quad);

Implement Dialogues

People need to be able to talk to each other. Old REGoth had a quite complete implementation of this feature, although it got a bit messy.

Full Scene-Cache not working

You should be able to load everything from cache, the full scene, that is. There is no need to ever open the .ZEN-file again after the caching mechanism went through it. Loading from cache is orders of magnitude faster than relaying on the .ZEN-file since I think it uses multithreading under the hood.

However, there is a problem with the physics mesh of the world: If we load the world-mesh from cache, the physics mesh seems broken and does not do any collision with other objects.

Some animations are not imported correctly

While animations like S_RUNL work fine, there are some which just don't do anything, like for example T_STRAFEL. It just has 0 animation frames for some reason and thus does not work.
Should be an importer-problem inside BsZenLib.

Animation import-code has grown a lot, I'm already sorry for that.

Node-Attachments are not placed correctly if no animation is playing

This causes seats facing the wrong way, chests being broken, all kinds of funny things. Maybe even the flying bookshelves?

I observed that node-attachments work fine once an animation starts playing. Should not be a problem with most stuff, since everything usually has at least a 1-frame animation, which does not appear to be working though.

Make default constructors used for RTTI private

A lot of classes inheriting directly or indirectly from IReflectable have a default constructor that is only used for RTTI and should not be accessible as part of the public interface. Due to the limitations of the current implementation, this default constructor is forced to be public like

A.hpp

class A
{
public:
    A(parameters...);
    ...

public:             // FIXME: RTTI protected/private
     A() = default; // For RTTI
}

The need to make it public originates from the macro REGOTH_IMPLEMENT_RTTI_CLASS_FOR_REFLECTABLE which is used in the accompanying RTTI class and models instantiation of a dummy instance like

bs::SPtr<bs::IReflectable> newRTTIObject() override          
{                                                            
  return bs::bs_shared_ptr_new<A>();                 
}   

To solve this issue, we could implement a scheme like bs::f does, which adds a static createEmpty method to the class itself:

A.hpp

class A
{
public:
    A(parameters...);
    ...

public:
    static bs::SPtr<A> createEmpty();

private:
     A() = default; // For RTTI
}

A.cpp

bs::SPtr<A> A::createEmpty()
{
    return bs::bs_shared_ptr(new (bs::bs_alloc<A>()) A());
}

The instantiation in the RTTI class could then be implemented like

bs::SPtr<bs::IReflectable> newRTTIObject() override          
{                                                            
  return A::createEmpty();                 
}   

Can only Sneak-Strafe right

It seems like it is only possible to strafe right while sneaking (X-key), although the correct animations seem to be used. Actually, since everything is mirrored in REGoth, it is more lilely that the Left-Animation works and the Right-Animation has a problem.

Look at how the strafe-animation is defined in the model script HumanS.mds:

ani("t_SneakStrafeL" 1 "s_Sneak" 0.1 0.1 M. "Hum_SneakStrafeLR_M01.ASC" F 1)
aniAlias ("t_SneakStrafeR" 1 "s_Sneak"	 0.1 0.1 M. "t_SneakStrafeL" R)

t_SneakStrafeR is just t_SneakStrafeL played in reverse (That R at the end), which is not implemented yet. So since the animation is not reversed, it's going into the wrong direction.

Playing animations in reverse has likely to be implemented around here:

void VisualSkeletalAnimation::playAnimationClip(HZAnimationClip clip)
{
using namespace bs;
throwIfNotReadyForRendering();
if (clip)
{
if (isClipLooping(clip))
{
mSubAnimation->setWrapMode(bs::AnimWrapMode::Loop);
}
else
{
mSubAnimation->setWrapMode(bs::AnimWrapMode::Clamp);
}
bs::INT32 layer = getClipLayer(clip);
if (layer > 0)
{
// bs::gDebug().logDebug(bs::StringUtil::format(
// "[VisualSkeletalAnimation] Layered animation {1} not implemented", clip->getName()));
// Commented out: Doesn't work yet
// mSubAnimation->blendAdditive(clip, 1.0f, 0.0f, (bs::UINT32)layer);
mSubAnimation->play(clip->mClip);
}
else
{
mSubAnimation->play(clip->mClip);
}
}
else
{
mSubAnimation->stopAll();
}
}

There is a flag which indicates whether the animation should be reversed but I'm not sure whether that's evaluated and actually set in ZenLib:

https://github.com/REGoth-project/BsZenLib/blob/84194ea45d7b53bc16ddaea1fb616496e2675380/include/BsZenLib/ZenResources.hpp#L160-L166

Objects are too bright

While the worldmesh looks correct now, objects are just fullbright.

image

In the original game, an object does a raycast downwards from somewhere in the bounding box to the worldmesh to see how bright the vertex lighting is on that spot. It then uses that brightness value for the whole object.

An example of that can be found in the old REGoth repository:

https://github.com/REGoth-project/REGoth/blob/b3c483747c869524e679b90f8d86ef5160b4c0bf/src/engine/World.cpp#L457-L475

To actually display the brightness, a Color-variable of type float4 should be added to shader World.bsl which should then be multiplied with the diffuse color of the object or whatever works.

Casting the ray and accessing the material can be done by the VisualStaticMesh-component for now, but we will need that functionality for other components as well, so we might as well create a very basic Visual-component to serve as a base class to VisualSkeletalAnimation, VisualStaticMesh and the others.

Another issue is that the original applied some static directional lighting to the objects (not the world-mesh!) so we might need to make shader variants supporting that to make it look right.

Find objects near a point in the world *fast*!

Right now we don't have any kind of acceleration structure to find stuff being near a character. We would have to query all the objects every time and that's just too slow to do for so many characters.

Usecase

Imagine figuring out which items are close to the character so we can take on into focus (Draw it's name on top of it).

Also monsters will later need to check whether a character is within a certain range for them to get angry.

Some ideas on how this could be implemented

I think we can get away with only taking objects into account which have the Focusable-component attached to them.

The class GameWorld has a list of all important objects in the scene. To keep the GameWorld-class clean, I would propose creating a small class which is then instantiated inside GameWorld, for example (pseudo code):

class FocusablesInRange
{
    HFocusable findClosestFocusableWithinRadius(position, radius);
    bs::Vector<HFocusable> findFocusablesWithinRadius(position, radius);

    // ...
};

For the actually searching, the original game uses a BSP-Tree. We don't have that at hand here and we actually don't want one. Spatial Hashing is much easier to implement! A Quad-tree should work too (I don't think we would benefit much from taking the Y-axis into account since gothics worlds are mostly flat).

Spatial Hashing

Spatial hashing is really simple: It divides the world into cells, which can be looked up easily. To figure out the cell of an object, one can divide the position by the cell-size and cut the fractional part:

cellX = (bs::INT32)(position.x / CELL_SIZE)
cellY = (bs::INT32)(position.y / CELL_SIZE)

The two resulting coordinates can then be used as keys into a hashmap. This could be a standard hash map like

bs::Map<std::pair<bs::INT32, bs::INT32>, bs::Vector<HFocusable>>

or maybe a MultiMap is worth looking at.

Adding, removing and updating objects

A possible solution is to add

  • GameWorld::onMoveFocusable(HFocusable focusable, ... previousPosition)
  • GameWorld::onDestroyFocusable(HFocusable focusable)

methods, which get called from the Focusable::onInitialized(), Focusable::onTransformChangedorFocusable::onDestroyed()`.

When a Focusable was moved into a new cell, the hash-map entry of the previous cell needs to be removed, and added into the new cell.

Of course, if you have better ideas on how to solve this, go ahead and implement them! This is only what came to my mind so far.

Play Sounds via Script

One of the simplest forms of how a sound is played is the Level Up sound, which is triggered by calling the script external void Snd_Play(string wav_name).

That external should simply play the specified .WAV file without any fancy 3D audio.

Jumping does not make the Character gain height

I guess gravity should be turned of for while a Jumping animation is playing. Right now we're not even doing proper acceleration, but what we do can be found here:

// Note: Gravity is acceleration, but since the walker doesn't support falling, just apply it
// as a velocity FIXME: Actual gravity!
const float frameDelta = bs::gTime().getFixedFrameDelta();
bs::Vector3 gravity = bs::Vector3(0, -9.81f, 0); // gPhysics().getGravity();
auto flags = mCharacterController->move(rootMotion + gravity * frameDelta);

The harder part of this issue is to find out for which animations the gravity should be disabled. There is a FLY flag on some animations inside HumanS.mds, of which I thought it would be only used for actual flying creatures like Bloodflys. Wasn't there some gravity on Bloodflys as well?

Save game inefficient

From Gitter:

Q:

On my system this call
world->save(SAVEGAME);
blocks and prevents the game from starting. I did some debugging and there is some recursive function call inside bs code.

A:

the save call takes ages for me when I run via the debugger. It's totally fine from the command line though. Should also not matter if you load a small world like OLDMINE. Otherwise you can just comment it out for now, but we should figure out what's taking it so long

REGoth crashes due to not yet loaded resources

Steps to reproduce:

  1. Use current master (2d71e24)
  2. Load ADDONWORLD.ZEN (Gothic 2) in the world viewer and make sure the init scripts are run (world->runInitScripts();)
  3. Quit the world viewer
  4. Start the world viewer without deleting the cache

An exception with the description Trying to access a resource that hasn't been loaded yet. will be raised in the function ModelScriptFile::_buildMeshesByNameMap by the call bs::String nameUpperCase = m->getName();.

The exception is most likely a sign that resources are accessed which are not saved as part of the prefab. The "hasn't been loaded yet" is a bit misleading here, as those resources will never be loaded.

The display name of the affected ModelScriptFile is "SCAVANGER" if that helps.

Load MS-ADPCM compressed WAVs

Dialogue lines are stored as Microsoft ADPCM compressed .WAV-files. If bsf cannot load those right away, we need to convert the files ourselfs.

This issue can be closed if it turns out converting ADPCM to RAW samples is not needed as discussed in issue #93.

Document Sky Rendering

There should be a chapter in the documentation explaining how sky rendering works.

Raw Background Color:
Bildschirmfoto von 2019-08-07 20-56-41

Additive-blended Color-Layer:
Bildschirmfoto von 2019-08-07 20-55-54

Alpha-blended Clouds-Layer:
Bildschirmfoto von 2019-08-07 20-54-58

Clouds-Layer without Color-Layer looks dull:
Bildschirmfoto von 2019-08-07 20-58-41

Color-Layer without additive blending (Mesh is a Dome:
Bildschirmfoto von 2019-08-07 21-05-38

Implement Interactive Objects (Mobs)

Characters need to be able to interact with certain objects like Benches, Beds, Chests and so on. Old REGoth had some support for that but that was rather buggy and incomplete. To get the basics going the old sourcecode can still serve as a base to look at.

This is not an easy task, as a lot of research and knowledge about the engine is needed.

Render Distance Fog

In Gothic, distance fog serves as a way to limit the draw distance. Also it looks nicer:

The fog itself is just simple linear fog calculated by taking the distance of the camera position to the currently shaded vertex. The distance where the fog should start (near) and where it should end (far) are already calculated here:

mSkyColoring->calculateFogDistanceAndColor(near, far, fogColor);
// TODO: Use fog near and far
(void)near;
(void)far;

It seems like bsf does not support Fog at the moment, and even if it did we'd most likely have to implement it into our custom shaders anyways: https://github.com/REGoth-project/REGoth-bs/blob/master/content/shaders/World.bsl

Implement Sky

Gothic supports two modes for it's sky:

  • Huge flat plane with the sky-texture assigned (used by G1, selectable in G2)
    Flat plane

  • Dome-mesh with the sky-texture and some color-blending to simulate the horizon (only in G2)
    Dome

Both of these have been implemented in old REGoth. The implementation decouples drawing from sky-logic and can be used as a reference.

We should probably use scene objects instead of rendering the meshes on our own though.

Simple Pathfinding

We need some simple algorithm to find the shortest path from one Waypoint to another on the waynet. The algorithm should return the list of waypoints which need to be walked to in the correct order.

See the documentation on Waynets for more information.

Add Bob-Shadow under Characters

In the original game, characters have a small round shadow under them. This is done by casting a
ray downwards from the character and aligning a plane showing the shadow-texture with the hit-point.

I don't know how far the shadow reaches or whether it fades once the character is too far away. You'd need to fire up good ol' Gothic yourself to see whether that is the case.

Bob Shadow

This should be implemented by a component, which:

  • Creates a sub-object for the shadow-plane,
  • Loads the plane-mesh and adds it as renderable to the sub-object (There should be a builtin-mesh in bsf),
  • Loads the Shadow-texture from the Virtual File System via. BsZenLib,
  • Performs the Rayscast every frame and positions the sub-object accordingly.

or

Libretro Core

Dear team,
please consider developing a Libretro Core to be used with Retroarch.

World-Mesh is half-imported even though it is cached

When importing a ZEN-file, the packMesh method should only be called if the world-mesh has not already been cached:

static bool importZEN(const bs::String& zenFile, OriginalZen& result)
{
ZenLoad::ZenParser zenParser(zenFile.c_str(), gVirtualFileSystem().getFileIndex());
if (zenParser.getFileSize() == 0) return false;
zenParser.readHeader();
result.fileName = zenFile;
zenParser.readWorld(result.vobTree);
// FIXME: Don't pack the mesh if it was already cached, packing takes a long time...
zenParser.getWorldMesh()->packMesh(result.worldMesh, 0.01f);
return true;
}

To fix this, the module has to be re-structured a bit so that the packing happens after checking for the cache. Packing actually takes a long time, so this will improve loading speeds in case the world mesh has already been cached.

Found a Rock without Collision

This could be either a bug in our code or Piranha Bytes forgot to set the collision flag.

Either way, it would be nice if someone could check whether there is collision in the original game. If so, we need to hunt down the bug.

This is the Rock in question:
Rock without collision

It's in ADDONWORLD.ZEN just left when you leave the temple where you start from.
Remember that in REGoth everything is mirrored, so you'd have to go right in the original game!

Implement Swimming

If a Character moves into a body of Water, they should start Wading and then Swimming if the water gets too deep.

Both Wading and Swimming are implemented as Walk-States, which should already be working. However, the correct Walk-State needs to be set, depending on the depth of water.

Note for the implementer: You will need a depth-value for each of those:

  1. Going into shallow water - start Wading
  2. Going out of shallow water - stop Wading
  3. Going into deep water - start Swimming
  4. Going out of deep water - start Wading

The "going out of.." depths need to be smaller than the "going into.." depths so quickly switching
between two states is not possible if the character stops right on the edge between them.

The CharacterAI could be a good place to implement this.

Commandline interface to REGoth

Right now, each sample just defines the world it is supposed to load. While this makes sense for some specialized samples, some are so generic, that the user should be able to choose the world to load from the commandline.

For example:

./REGothWorldViewer ~/games/Gothic2 -w ADDONWORLD

Other flags for loading .mod-packages would also be helpful.

Automatically find Startpoint

Right now, the Startpoint to insert the Hero at is hardcoded inside the sample applications, like here:

if (!worldPrefab)
{
world = GameWorld::importZEN(WORLD);
HCharacter hero = world->insertCharacter("PC_HERO", "START_DRAGONISLAND");
hero->useAsHero();
hero->SO()->addComponent<CharacterKeyboardInput>();
world->runInitScripts();

Unfortunately, the name of the startpoint differs between ZENs, but there is only supposed to be a single one of them in each ZEN I think. As far as I know, the original engine simply searches for an object of class zCVobStartpoint.

The code which first touches the startpoint on import is here:

if (!worldPrefab)
{
world = GameWorld::importZEN(WORLD);
HCharacter hero = world->insertCharacter("PC_HERO", "START_DRAGONISLAND");
hero->useAsHero();
hero->SO()->addComponent<CharacterKeyboardInput>();
world->runInitScripts();

A simple solution would be to rename the scene object just STARTPOINT and then search for it by name. I'm not sure whether the actual name of the startpoint is important as there should be only one anyways. We could also pass it to the GameWorld somehow. Although I don' like making a setter for that.

Jumping animation can get stuck

Go into walk mode, jump and then press forward mid jump and you get stuck in the jump animation until you let go of forward. There must be a problem with the transition between the weird STAND state, which does not really exist, and WALK.

Must be somewhere around in that file or the related ones: https://github.com/REGoth-project/REGoth-bs/blob/master/src/components/CharacterAI.cpp

This also works for walk/sneak when holding forward in the middle of the backup move.

Exploding triangles

Sometimes one can see messed up triangles, going all over the place. You cannot move away from them, they just stay attached to the camera.

I have no idea what that is caused by, but I can see it happen in the REGothWorldViewer where many characters are added to the world. Probably one of the NPCs is broken, we should find out which one it is.

Pick up items from the ground

The player should be able to pick up items laying on the ground. This usually goes as follows:

  1. Take a nearby item into focus
  2. Play an animation depending on where that item is
  3. During that animation, remove the item from the world
  4. Place the item into the inventory
  5. Return to normal idle state

As a starting point, check out the CharacterEventQueue component, which handles gameplay-related things. The event you'd have to implement is ManipulateMessage::ST_TakeObject.

Getting the item in focus

Until #66 is not done, we don't have any "focusing" (Edit: Focusing was implemented in #92, just not as fast). However, that doesn't put this issue on hold. Just use GameWorld::findItemsInRange() with a short range and take anything from that.

Playing the animations

The CharacterAI-Component should be extended with a method to play the pickup animation. I'm not sure whether the pickup animation uses animation-events to trigger the actual pickup, or whether the original just uses "when the animation is at 50% done" or something.

Remove the item from the world

Removing stuff from the world is not possible right now and thus needs to be implemented. I think we should let the GameWorld handle that for us, so a GameWorld::removeItem(HItem item) method should take care of that.

Place the item into the inventory

We've got an Inventory component inside #60, which should be merged soon.

Return to normal idle state

Returning to the normal idle state should be taken care of by the animation system, nothing to do here!

Jumpy or incorrectly rotated animations

There seems to be an issue with the animation importer which causes weird behavior when playing some animation frames. For example, sometimes during the normal Run Forward-animation, a leg goes flying.

Also one of T_RUNTURNL or T_RUNTURNR makes the character face the wrong direction.

Make NPCs able to pick-up items

(#68 should be resolved first)

NPCs can pick up items via the script external AI_TakeItem, like here:

https://github.com/GothicII/GOTHIC-MOD-Development-Kit/blob/4071a70b3a8943e374ccbf886986e494b4be0858/gothic/_work/data/Scripts/content/AI/ZS_Human/ZS_GetBackItem.d#L51

The external itself pushes three event messages into the CharacterEventQueue:

  • Let the character move to the the position of that item. (pushGotoObject)
  • Turn towards that item. (pushTurnToObject, not implemented yet)
  • Pick it up. (pushTakeItem, see #68)

To implement externals, see DaedalusVMForGameWorld.cpp.

Implement Lightmapping

For houses, caves and the like, lightmaps are used in the original game. The lightmap is applied to the world mesh geometry, which has a second set of texture coordinates it uses a lightmap.

A formula is then used to convert global coordinates to the lightmap texel to be used. I have some code laying around to do that and actually implemented that once in old REGoth. Seems like I never pushed it though?

Implement HUD

The ingame-hud needs to be implemented.

image

This includes:

  • Health-Bar
  • Mana-Bar
  • Enemy Health-Bar
  • Focus Text

UI like Inventory, Main-Menu and Stats-Screen should not be handled by the hud.

Divide the cache per game type to avoid clashes

Currently, the caches of Gothic and Gothic II may clash. It would be best to separate them by introducing a subfolder in cache, like so:

bin/cache/
|-gothic1/
| ` <Gothic 1 cache files>
`-gothic2/
  ` <Gothic 2 cache files>

This doesn't solve the problem with mods. Maybe we could calculate a game-type hash by concating the original game + the mods in alphabetic order and hash that, which will then be the cache key to look for (i.e. a folder with that name in cache/)

Backing up in Sneak-Mode

Were you able to go backwards while sneaking in the original game?

Right now you will just perform a normal step backwards while sneaking in REGoth. This isn't correct either way. So to close this issue we need to:

  • Check how sneaking behaves in the original.
  • Implement that behavior in REGoth

The entrypoint to Taking a step backwards is here:

bool CharacterAI::goBackward()
{
if (!isStateSwitchAllowed()) return false;
return tryPlayTransitionAnimationTo("T_JUMPB");
}

As of now, isStateSwitchAllowed() will just return true for T_JUMPB regardless of the state the character is in, or anything starting with T_ really, which is why stepping backwards is possible while sneaking.

Material-Flag "No Collision" is ignored

There is a flag inside the original materials in which the level-creator can set that a certain submesh should not use collision detection. This is mostly used for plants where the characters can walk through, like these:

Plants

This is a follow-up to #30.

Hard Mode

Since a lot of people liked this idea, it would be a great thing to implement a "hard mode" where the world meshes are mirrored.

Reference: #49

Load uncompressed WAV files

The games sounds come as regular .WAV files which are stored within the VDFS. Actual sound effects should even be uncompressed, while dialogue lines use Microsoft ADPCM (See #94).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.