Skip to content

Commit ace0c8a

Browse files
committed
feat: basic framework
1 parent 96521e7 commit ace0c8a

11 files changed

+271
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dist
2+
node_modules
3+
yarn.lock

package.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "netcode",
3+
"version": "1.0.0",
4+
"description": "A js game framework for state-synchronization.",
5+
"main": "dist/netcode.js",
6+
"types": "dist/index.d.ts",
7+
"repository": "https://github.com/netcodejs/netcode",
8+
"author": "moruiyi",
9+
"license": "GPL-3.0-or-later",
10+
"devDependencies": {
11+
"rollup": "^2.39.0",
12+
"rollup-plugin-typescript2": "^0.30.0",
13+
"tslib": "^2.1.0",
14+
"typescript": "^4.1.5"
15+
},
16+
"scripts": {
17+
"build": "yarn run rollup -c"
18+
}
19+
}

rollup.config.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import typescript from 'rollup-plugin-typescript2'
2+
3+
export default {
4+
input: "src/index.ts",
5+
output: {
6+
file: "dist/netcode.js",
7+
format: "es"
8+
},
9+
plugins: [typescript()]
10+
}

src/component.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Macro } from "./macro";
2+
3+
export let ComponentClassType: any[] = []
4+
export function Component<T extends { new(): any }>(target: T) {
5+
target.prototype.__classId__ = ComponentClassType.push(target) - 1;
6+
}
7+
8+
export function Param(type: ParamType): PropertyDecorator {
9+
return function(target: any, propertyKey: string | symbol) {
10+
if (!target.__schema__)
11+
target.__schema__ = { count: 0, props: {} }
12+
const s = target.__schema__;
13+
14+
const paramIndex = s.count++;
15+
const v = { propertyKey, type, paramIndex };
16+
s.props[paramIndex] = v
17+
s.props[propertyKey] = v
18+
}
19+
}
20+
21+
export enum ParamType {
22+
i8, u8, i16, u16, i32, u32, i64, u64, int, long, float, double, string, bool, f32, f64
23+
}
24+
25+
export interface IComponent {
26+
owner?:number;
27+
__schema__?: Record<string | number, string | number>
28+
29+
onLoad?(): void;
30+
onStart?(): void;
31+
onDestroy?(): void;
32+
33+
update?(): void;
34+
fixedUpdate?(): void;
35+
lateUpdate?(): void;
36+
}

src/data/serializable.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export interface Serializable<T extends String | ArrayBuffer> {
2+
ser(buffer: DataBuffer<T>): void;
3+
deser(buffer: DataBuffer<T>): void;
4+
}
5+
6+
export interface DataBuffer<T extends String | ArrayBuffer> {
7+
8+
}

src/domain.ts

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { Entity } from "./entity";
2+
import { Macro } from "./macro";
3+
4+
class EntityNotValidError extends Error {}
5+
class EntityRepeatRegisteredError extends Error {}
6+
class EntityGroupOutOfRangeYouCanOpenAutoResize extends Error {}
7+
class DomainDefinition {
8+
private _entities: (Entity | null)[]
9+
private _entityVersion: number[]
10+
private _destroyEntityId: number[]
11+
private _entityIdCursor = 0;
12+
13+
constructor(public capacity = 50, public autoResize = true) {
14+
this._entities = new Array<Entity>(capacity);
15+
this._entityVersion = new Array<number>(capacity);
16+
this._entityVersion.fill(0);
17+
this._destroyEntityId = new Array<number>(capacity);
18+
}
19+
20+
reg(entity: Entity) {
21+
if (this.isValid(entity))
22+
throw new EntityRepeatRegisteredError(entity.toString());
23+
if (this._entityIdCursor == this.capacity && this.autoResize)
24+
this.resize(Math.ceil(this.capacity * 1.5))
25+
else
26+
throw new EntityGroupOutOfRangeYouCanOpenAutoResize(
27+
`Domain: capacity: ${this.capacity}; ` + entity.toString());
28+
this._unlockEntity(entity);
29+
entity.id = this._getEntityId();
30+
entity.version = this._entityVersion[entity.id];
31+
this._lockEntity(entity);
32+
this._entities[entity.id] = entity;
33+
}
34+
35+
unreg(entity: Entity) {
36+
if (!this.isValid(entity))
37+
throw new EntityNotValidError(entity.toString());
38+
this._entityVersion[entity.id]++;
39+
this._destroyEntityId.push(entity.id);
40+
this._entities[entity.id] = null;
41+
}
42+
43+
resize(newSize: number) {
44+
const oldSize = this.capacity;
45+
this._entities.length = newSize;
46+
this._entityVersion.length = newSize;
47+
this._entityVersion.fill(0, oldSize, newSize);
48+
this.capacity = newSize;
49+
}
50+
51+
isValid(entity: Entity) {
52+
return entity.id != Macro.NULL_NUM
53+
&& entity.version != Macro.NULL_NUM
54+
&& entity.version == this._entityVersion[entity.id]
55+
}
56+
57+
private _getEntityId() {
58+
return this._destroyEntityId.length > 0
59+
? this._destroyEntityId.unshift()
60+
: this._entityIdCursor++;
61+
}
62+
63+
private _lockEntity(entity: Entity) {
64+
Object.defineProperties(entity, {
65+
"id": { writable: false },
66+
"version": { writable: false }
67+
})
68+
}
69+
70+
private _unlockEntity(entity: Entity) {
71+
Object.defineProperties(entity, {
72+
"id": { writable: true },
73+
"version": { writable: true }
74+
})
75+
}
76+
}
77+
78+
export const Domain = new DomainDefinition();

src/entity.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Macro } from "./macro";
2+
3+
export class Entity {
4+
id = Macro.NULL_NUM
5+
version = Macro.NULL_NUM
6+
constructor() {
7+
Object.seal(this);
8+
}
9+
10+
toString() {
11+
return `Entity: id=${this.id},version=${this.version}`
12+
}
13+
}

src/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from './component';
2+
export * from './entity';
3+
4+
import './test'

src/macro.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const Macro = {
2+
NULL_NUM: -1,
3+
NULL_STR: "NULL"
4+
}

src/test.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Component, IComponent, Param, ParamType, ComponentClassType } from "./component";
2+
3+
@Component
4+
export class ViewComponrnt implements IComponent {
5+
@Param(ParamType.int)
6+
width: number = 0;
7+
@Param(ParamType.int)
8+
height: number = 0;
9+
10+
onLoad() {
11+
12+
}
13+
}
14+
15+
@Component
16+
export class LogicComponent {
17+
@Param(ParamType.bool)
18+
alive: boolean = false
19+
}
20+
21+
let v1 = new ViewComponrnt();
22+
let v2 = new ViewComponrnt();
23+
24+
let l1 = new LogicComponent();
25+
// @ts-ignore
26+
console.log(v1.__schema__, v2.__schema__, v1.__schema__ === v2.__schema__, l1.__schema__, ComponentClassType);

tsconfig.json

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"include": ["src"],
3+
"compilerOptions": {
4+
/* Visit https://aka.ms/tsconfig.json to read more about this file */
5+
/* Basic Options */
6+
// "incremental": true, /* Enable incremental compilation */
7+
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
8+
"module": "ESNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
9+
"lib": ["ES2015"], /* Specify library files to be included in the compilation. */
10+
// "allowJs": true, /* Allow javascript files to be compiled. */
11+
// "checkJs": true, /* Report errors in .js files. */
12+
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
13+
"declaration": true, /* Generates corresponding '.d.ts' file. */
14+
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
15+
// "sourceMap": true, /* Generates corresponding '.map' file. */
16+
// "outFile": "./", /* Concatenate and emit output to single file. */
17+
// "outDir": "./", /* Redirect output structure to the directory. */
18+
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
19+
// "composite": true, /* Enable project compilation */
20+
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
21+
// "removeComments": true, /* Do not emit comments to output. */
22+
// "noEmit": true, /* Do not emit outputs. */
23+
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
24+
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
25+
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
26+
27+
/* Strict Type-Checking Options */
28+
"strict": true, /* Enable all strict type-checking options. */
29+
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
30+
// "strictNullChecks": true, /* Enable strict null checks. */
31+
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
32+
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
33+
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
34+
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
35+
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
36+
37+
/* Additional Checks */
38+
// "noUnusedLocals": true, /* Report errors on unused locals. */
39+
// "noUnusedParameters": true, /* Report errors on unused parameters. */
40+
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
41+
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
42+
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
43+
44+
/* Module Resolution Options */
45+
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
46+
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
47+
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
48+
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
49+
// "typeRoots": [], /* List of folders to include type definitions from. */
50+
// "types": [], /* Type declaration files to be included in compilation. */
51+
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
52+
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
53+
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
54+
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
55+
56+
/* Source Map Options */
57+
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
58+
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
59+
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
60+
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
61+
62+
/* Experimental Options */
63+
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
64+
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
65+
66+
/* Advanced Options */
67+
"skipLibCheck": true, /* Skip type checking of declaration files. */
68+
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
69+
}
70+
}

0 commit comments

Comments
 (0)