Open TIMONz1535 opened 2 years ago
Adding server/client bools should is easy. They can just be added to https://github.com/lolleko/gmod-typescript/blob/master/types/extras.d.ts
ENT, SWEP, GM are a different story, however. These have some weird file based scoping. So declaring them globally can cause issues.
Additionally, even if they would exist, it is impossible to access them properly in vanilla TS, in the way Gmod requires (function ENT:Spawn() end .....
) again because of the odd file based scoping.
We had some discussions about this on discord:
https://discord.com/channels/515854149821267971/515854150257344524/571792067324280832
https://discord.com/channels/515854149821267971/515854150257344524/719667301086920717
I think we will need a custom decorator, similar to this one for DotA abilities https://github.com/ModDota/TypeScriptAddonTemplate/blob/master/src/vscripts/lib/dota_ts_adapter.ts#L34 https://github.com/ModDota/TypeScriptAddonTemplate/blob/master/src/vscripts/abilities/heroes/meepo/earthbind_ts_example.ts to attach functions from entity files to the ENT/SWEP table. Maybe even a custom TSTL plugin.
I found this solution https://github.com/glua-addon-types/glua-types
https://github.com/SupinePandora43/Trailers-Reborn - there are no entities here... https://github.com/rwilliaise/gmodtf2sweps - it's almost empty here, but it gave me an idea how to implement a weapon class (see below)
declare const SERVER: boolean
declare const CLIENT: boolean
declare const MENU: boolean
declare const GAMEMODE: Gamemode
declare const GM: Gamemode
This means that they are available everywhere, and you must understand where you write your code. In general, it was the same on Lua...
I had to modify the declarations a bit
declare const SWEP: Weapon
declare const ENT: Entity
type Entity = IEntity & EntityFuncs & EntityHooks
type Weapon = IWeapon & WeaponFuncs & WeaponHooks
this allowed me to write like this
AddCSLuaFile()
SWEP.ViewModel = Model("models/weapons/c_arms_animations.mdl")
SWEP.WorldModel = Model("models/MaxOfS2D/camera.mdl")
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = "none"
and this
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PrintName = "Fog Editor"
ENT.Category = "Editors"
ENT.Initialize = function () {
this.SetMaterial("gmod/edit_fog")
if (CLIENT) {
}
this.UpdateTransmitState = function (this: Entity): TRANSMIT {
return TRANSMIT.TRANSMIT_ALWAYS
}
}
ENT.UpdateTransmitState = function () {
return TRANSMIT.TRANSMIT_ALWAYS
}
ENT.SetMaterial = function (): string {
return "wtf"
}
but all the functions that I write completely ignore the original declarations (except when some value is returned, like UpdateTransmitState), an example I can write anything in SetMaterial
I can write something more interesting, like this. In theory, it should automatically redirect everything to SWEP. I didn't test, just watched the Lua code. The constructor is needed only if I don't declare all values as static
. The main thing is not to forget that this is a fake, not a real class.
declare const set: LuaTableSet<AnyNotNil, AnyNotNil, any>
interface ScriptedWeapon extends Entity { }
class ScriptedWeapon {
// redirect for class methods from prototype and constructor
__newindex(k: any, v: any) {
if (k != "____constructor")
set(SWEP, k, v)
}
// redirect for static variables from class
static __newindex(k: any, v: any) {
set(SWEP, k, v)
}
}
class Pistol extends ScriptedWeapon {
constructor(name: string) {
super()
this.Initialize = function () {
this.SetMaterial("gmod/edit_fog")
}
this.PrintName = name
this.AdminOnly = true
this.Spawnable = true
}
Initialize(this: Entity): void {
}
UpdateTransmitState(this: Entity): TRANSMIT {
return TRANSMIT.TRANSMIT_ALWAYS
}
SetupDataTables(this: Entity): void {
}
// you can easily make your own variables and methods
// with SWEP/ENT you will have to cast it to `any` or `unknown`
MyOwnValue1?: string
MyOwnValue11: string = "kek"
AdminOnly: boolean;
PrintName: string = "Kek"
static Category: string = "Kek2"
}
new Pistol("kekos")
Lua provides an opportunity to mutate the ENT methods/hooks, but I would like to implement the Entity. In a TypeScript, the implements
requires all methods/properties... I'm not good at this :(
Oh yes, I haven't come up with anything smarter for client/server separation.
if (CLIENT) {
class Pistol2 extends ScriptedWeapon {
static Category: string = "Kek2"
Initialize(this: Entity): void { }
DrawModel(this: Entity): void { }
}
new Pistol2()
}
else {
class Pistol2 extends ScriptedWeapon {
static Category: string = "Kek2"
Initialize(this: Entity): void { }
OnRemove(this: Entity): void { }
}
new Pistol2()
}
I added
declare const SERVER: boolean;
declare const CLIENT: boolean;
declare const MENU: boolean;
declare const GAMEMODE: Gamemode;
declare const GM: Gamemode;
declare const SWEP: Weapon;
declare const ENT: Entity;
in v0.3.0 unitl we can come up with something better. Also keep in mind that declarations for hooks are not yet generated.
There is no way to control script workflow with a SERVER/CLIENT realms. Its not exists in TypeScript.
https://wiki.facepunch.com/gmod/States
There are also some global variables, such as ENT, SWEP, GM. However, I have no idea how to implement them correctly, because they will be visible in the entire TypeScript code. TypeScriptToLua uses
globalThis
for _G alias.globalThis
implemented by TypeScript itself.https://wiki.facepunch.com/gmod/Global_Variables
Minor. Garry's mod also have some constants (vector_origin, vector_up) at the bottom of the page. I don't like their names, I'd rather make my own like ZeroVector, ForwardVector and other. But perhaps it can be useful to someone. I think you will decide for yourself whether you need to spend time on this.